@studiometa/ui 1.6.0 → 1.7.0

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.
Files changed (69) hide show
  1. package/Accordion/Accordion.d.ts +1 -1
  2. package/Accordion/Accordion.js.map +1 -1
  3. package/Action/Action.d.ts +1 -1
  4. package/Action/Action.js.map +1 -1
  5. package/AnchorNav/AnchorNav.d.ts +1 -1
  6. package/AnchorNav/AnchorNav.js.map +1 -1
  7. package/AnchorScrollTo/AnchorScrollTo.d.ts +1 -1
  8. package/AnchorScrollTo/AnchorScrollTo.js.map +1 -1
  9. package/CircularMarquee/CircularMarquee.d.ts +1 -1
  10. package/CircularMarquee/CircularMarquee.js.map +1 -1
  11. package/Cursor/Cursor.d.ts +1 -1
  12. package/Cursor/Cursor.js.map +1 -1
  13. package/Data/DataBind.d.ts +1 -1
  14. package/Data/DataBind.js.map +1 -1
  15. package/Draggable/Draggable.d.ts +1 -1
  16. package/Draggable/Draggable.js.map +1 -1
  17. package/Fetch/Fetch.d.ts +1 -1
  18. package/Fetch/Fetch.js.map +1 -1
  19. package/Figure/Figure.d.ts +1 -1
  20. package/Figure/Figure.js.map +1 -1
  21. package/Figure/FigureShopify.d.ts +1 -1
  22. package/Figure/FigureShopify.js.map +1 -1
  23. package/Figure/FigureTwicpics.d.ts +1 -1
  24. package/Figure/FigureTwicpics.js.map +1 -1
  25. package/FigureVideo/FigureVideo.d.ts +1 -1
  26. package/FigureVideo/FigureVideo.js.map +1 -1
  27. package/FigureVideo/FigureVideoTwicpics.d.ts +1 -1
  28. package/FigureVideo/FigureVideoTwicpics.js.map +1 -1
  29. package/Frame/Frame.d.ts +1 -1
  30. package/Frame/Frame.js.map +1 -1
  31. package/Hoverable/Hoverable.d.ts +1 -1
  32. package/Hoverable/Hoverable.js.map +1 -1
  33. package/LargeText/LargeText.d.ts +1 -1
  34. package/LargeText/LargeText.js.map +1 -1
  35. package/LazyInclude/LazyInclude.d.ts +1 -1
  36. package/LazyInclude/LazyInclude.js.map +1 -1
  37. package/Menu/Menu.d.ts +1 -1
  38. package/Menu/Menu.js.map +1 -1
  39. package/Menu/MenuList.js +1 -0
  40. package/Menu/MenuList.js.map +2 -2
  41. package/Modal/Modal.d.ts +1 -1
  42. package/Modal/Modal.js.map +1 -1
  43. package/Panel/Panel.d.ts +1 -1
  44. package/Panel/Panel.js.map +1 -1
  45. package/Prefetch/AbstractPrefetch.d.ts +1 -1
  46. package/Prefetch/AbstractPrefetch.js.map +1 -1
  47. package/Prefetch/PrefetchWhenOver.d.ts +1 -1
  48. package/Prefetch/PrefetchWhenOver.js.map +1 -1
  49. package/Prefetch/PrefetchWhenVisible.d.ts +1 -1
  50. package/Prefetch/PrefetchWhenVisible.js.map +1 -1
  51. package/README.md +1 -1
  52. package/ScrollAnimation/ScrollAnimation.d.ts +1 -1
  53. package/ScrollAnimation/ScrollAnimation.js.map +1 -1
  54. package/ScrollReveal/ScrollReveal.d.ts +1 -1
  55. package/ScrollReveal/ScrollReveal.js.map +1 -1
  56. package/Sentinel/Sentinel.d.ts +1 -1
  57. package/Sentinel/Sentinel.js.map +1 -1
  58. package/Slider/Slider.d.ts +1 -1
  59. package/Slider/Slider.js.map +1 -1
  60. package/Sticky/Sticky.d.ts +1 -1
  61. package/Sticky/Sticky.js.map +1 -1
  62. package/Tabs/Tabs.d.ts +1 -1
  63. package/Tabs/Tabs.js.map +1 -1
  64. package/Transition/Transition.d.ts +23 -1
  65. package/Transition/Transition.js.map +2 -2
  66. package/decorators/withTransition.d.ts +11 -0
  67. package/decorators/withTransition.js +49 -0
  68. package/decorators/withTransition.js.map +2 -2
  69. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/Frame/Frame.ts"],
4
- "sourcesContent": ["import { Base, getClosestParent } from '@studiometa/js-toolkit';\nimport type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';\nimport { domScheduler, historyPush } from '@studiometa/js-toolkit/utils';\nimport { FrameAnchor } from './FrameAnchor.js';\nimport { FrameForm } from './FrameForm.js';\nimport { FrameTarget } from './FrameTarget.js';\nimport { FrameLoader } from './FrameLoader.js';\nimport type { FrameRequestInit, FrameTriggerEvent } from './types.js';\nimport { EVENTS } from './utils.js';\n\nexport interface FrameProps extends BaseProps {\n $children: {\n FrameAnchor: FrameAnchor[];\n FrameForm: FrameForm[];\n FrameTarget: FrameTarget[];\n FrameLoader: FrameLoader[];\n };\n $options: {\n history: boolean;\n requestInit: RequestInit;\n headers: Record<string, string>;\n };\n}\n\n/**\n * Frame class.\n * @link https://ui.studiometa.dev/-/components/Frame/\n */\nexport class Frame<T extends BaseProps = BaseProps> extends Base<T & FrameProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Frame',\n emits: Object.values(EVENTS),\n components: {\n FrameAnchor,\n FrameForm,\n FrameTarget,\n FrameLoader,\n },\n options: {\n history: Boolean,\n requestInit: Object,\n headers: Object,\n },\n };\n\n /**\n * DOM Parser to parse the new content to be injected.\n */\n domParser = new DOMParser();\n\n /**\n * Abort controller to prevent multiple simultaneous fetches.\n */\n abortController = new AbortController();\n\n /**\n * Header names.\n */\n headerNames = {\n ACCEPT: 'accept',\n X_REQUESTED_BY: 'x-requested-by',\n X_TRIGGERED_BY: 'x-triggered-by',\n USER_AGENT: 'user-agent',\n } as const;\n\n /**\n * Get uniq id.\n */\n get id() {\n return this.$el.id;\n }\n\n /**\n * The client used for the fetch request.\n */\n get client(): typeof fetch {\n return window.fetch.bind(window);\n }\n\n /**\n * Default request init.\n */\n get requestInit(): RequestInit {\n const { headerNames } = this;\n const { requestInit, headers } = this.$options;\n const requestedBy = '@studiometa/ui/Frame';\n\n return {\n ...requestInit,\n headers: {\n [headerNames.ACCEPT]: 'text/*',\n [headerNames.X_REQUESTED_BY]: requestedBy,\n [headerNames.USER_AGENT]: `${navigator.userAgent} ${requestedBy}`,\n ...requestInit.headers,\n ...headers,\n },\n };\n }\n\n /**\n * Get chidlren limited to the current instance.\n */\n getDirectChildren(name: keyof FrameProps['$children']) {\n const children = [];\n for (const child of this.$children[name]) {\n if (getClosestParent(child, this.constructor) === this) {\n children.push(child);\n }\n }\n return children;\n }\n\n /**\n * Fetch new content on frame-trigger.\n */\n onFrameAnchorFrameTrigger({ args: [url, requestInit] }: { args: FrameTriggerEvent['detail'] }) {\n this.fetch(url, requestInit);\n }\n\n /**\n * Fetch new content on frame-trigger.\n */\n onFrameFormFrameTrigger({ args: [url, requestInit] }: { args: [URL, FrameRequestInit] }) {\n this.fetch(url, requestInit);\n }\n\n /**\n * Update content on history back/forward navigation.\n */\n onWindowPopstate() {\n this.fetch(new URL(window.location.href), {\n headers: {\n [this.headerNames.X_TRIGGERED_BY]: 'popstate',\n },\n });\n }\n\n /**\n * Trigger FrameLoaders enter.\n */\n onFrameFetchBefore() {\n for (const loader of this.getDirectChildren('FrameLoader')) {\n loader.enter();\n }\n }\n\n /**\n * Trigger FrameLoaders leave.\n */\n onFrameFetchAfter() {\n for (const loader of this.getDirectChildren('FrameLoader')) {\n loader.leave();\n }\n }\n\n emitSync(event: string, trigger: FrameForm | FrameAnchor = null, ...args: any[]) {\n this.$emit(event, ...args);\n trigger?.$emit(event, ...args);\n }\n\n /**\n * Fetch given url.\n */\n async fetch(url: URL, requestInit: FrameRequestInit = {}) {\n this.emitSync(EVENTS.FETCH_BEFORE, requestInit.trigger, url, requestInit);\n\n this.abortController.abort();\n this.abortController = new AbortController();\n const init = {\n ...this.requestInit,\n ...requestInit,\n headers: {\n ...this.requestInit.headers,\n ...requestInit.headers,\n },\n signal: this.abortController.signal,\n };\n\n this.$log('fetch', url, init);\n this.emitSync(EVENTS.FETCH, init.trigger, url, init);\n\n try {\n const content = await this.client(url, init).then((response) => response.text());\n this.emitSync(EVENTS.FETCH_AFTER, init.trigger, url, requestInit, content);\n this.content(url, init, content);\n } catch (error) {\n this.emitSync(EVENTS.FETCH_AFTER, init.trigger, url, requestInit, error);\n this.error(url, init, error);\n }\n }\n\n /**\n * Dispatch the contents to update to their matching FrameTarget.\n */\n async content(url: URL, requestInit: FrameRequestInit, content: string) {\n this.$log('content', url, content);\n this.emitSync(EVENTS.CONTENT, requestInit.trigger, url, requestInit, content);\n\n const doc = this.domParser.parseFromString(content, 'text/html');\n const el = doc.querySelector(`#${this.id}`) ?? doc;\n const promises = [];\n\n // @todo inject styles and scripts from new <head>\n if (this.$options.history) {\n if (requestInit?.headers?.[this.headerNames.X_TRIGGERED_BY] !== 'popstate') {\n historyPush({ path: url.pathname, search: url.searchParams });\n }\n domScheduler.write(() => {\n if (doc.title) document.title = doc.title;\n });\n }\n\n for (const frameTarget of this.getDirectChildren('FrameTarget')) {\n promises.push(frameTarget.updateContent(el.querySelector(`#${frameTarget.id}`)));\n }\n\n await Promise.all(promises);\n\n this.emitSync(EVENTS.CONTENT_AFTER, requestInit.trigger, url, requestInit, content);\n\n // We need to update the root instance to make sure newly inserted\n // components are correctly detected and mounted. This avoid having\n // to declare all potentials component as children of the Frame component.\n await this.$root.$update();\n }\n\n /**\n * Handle errors.\n */\n async error(url: URL, requestInit: FrameRequestInit, error: Error) {\n this.$log('error', url, requestInit, error);\n this.emitSync(EVENTS.ERROR, requestInit.trigger, url, requestInit, error);\n }\n}\n"],
4
+ "sourcesContent": ["import { Base, getClosestParent } from '@studiometa/js-toolkit';\nimport type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';\nimport { domScheduler, historyPush } from '@studiometa/js-toolkit/utils';\nimport { FrameAnchor } from './FrameAnchor.js';\nimport { FrameForm } from './FrameForm.js';\nimport { FrameTarget } from './FrameTarget.js';\nimport { FrameLoader } from './FrameLoader.js';\nimport type { FrameRequestInit, FrameTriggerEvent } from './types.js';\nimport { EVENTS } from './utils.js';\n\nexport interface FrameProps extends BaseProps {\n $children: {\n FrameAnchor: FrameAnchor[];\n FrameForm: FrameForm[];\n FrameTarget: FrameTarget[];\n FrameLoader: FrameLoader[];\n };\n $options: {\n history: boolean;\n requestInit: RequestInit;\n headers: Record<string, string>;\n };\n}\n\n/**\n * Frame class.\n * @link https://ui.studiometa.dev/components/Frame/\n */\nexport class Frame<T extends BaseProps = BaseProps> extends Base<T & FrameProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Frame',\n emits: Object.values(EVENTS),\n components: {\n FrameAnchor,\n FrameForm,\n FrameTarget,\n FrameLoader,\n },\n options: {\n history: Boolean,\n requestInit: Object,\n headers: Object,\n },\n };\n\n /**\n * DOM Parser to parse the new content to be injected.\n */\n domParser = new DOMParser();\n\n /**\n * Abort controller to prevent multiple simultaneous fetches.\n */\n abortController = new AbortController();\n\n /**\n * Header names.\n */\n headerNames = {\n ACCEPT: 'accept',\n X_REQUESTED_BY: 'x-requested-by',\n X_TRIGGERED_BY: 'x-triggered-by',\n USER_AGENT: 'user-agent',\n } as const;\n\n /**\n * Get uniq id.\n */\n get id() {\n return this.$el.id;\n }\n\n /**\n * The client used for the fetch request.\n */\n get client(): typeof fetch {\n return window.fetch.bind(window);\n }\n\n /**\n * Default request init.\n */\n get requestInit(): RequestInit {\n const { headerNames } = this;\n const { requestInit, headers } = this.$options;\n const requestedBy = '@studiometa/ui/Frame';\n\n return {\n ...requestInit,\n headers: {\n [headerNames.ACCEPT]: 'text/*',\n [headerNames.X_REQUESTED_BY]: requestedBy,\n [headerNames.USER_AGENT]: `${navigator.userAgent} ${requestedBy}`,\n ...requestInit.headers,\n ...headers,\n },\n };\n }\n\n /**\n * Get chidlren limited to the current instance.\n */\n getDirectChildren(name: keyof FrameProps['$children']) {\n const children = [];\n for (const child of this.$children[name]) {\n if (getClosestParent(child, this.constructor) === this) {\n children.push(child);\n }\n }\n return children;\n }\n\n /**\n * Fetch new content on frame-trigger.\n */\n onFrameAnchorFrameTrigger({ args: [url, requestInit] }: { args: FrameTriggerEvent['detail'] }) {\n this.fetch(url, requestInit);\n }\n\n /**\n * Fetch new content on frame-trigger.\n */\n onFrameFormFrameTrigger({ args: [url, requestInit] }: { args: [URL, FrameRequestInit] }) {\n this.fetch(url, requestInit);\n }\n\n /**\n * Update content on history back/forward navigation.\n */\n onWindowPopstate() {\n this.fetch(new URL(window.location.href), {\n headers: {\n [this.headerNames.X_TRIGGERED_BY]: 'popstate',\n },\n });\n }\n\n /**\n * Trigger FrameLoaders enter.\n */\n onFrameFetchBefore() {\n for (const loader of this.getDirectChildren('FrameLoader')) {\n loader.enter();\n }\n }\n\n /**\n * Trigger FrameLoaders leave.\n */\n onFrameFetchAfter() {\n for (const loader of this.getDirectChildren('FrameLoader')) {\n loader.leave();\n }\n }\n\n emitSync(event: string, trigger: FrameForm | FrameAnchor = null, ...args: any[]) {\n this.$emit(event, ...args);\n trigger?.$emit(event, ...args);\n }\n\n /**\n * Fetch given url.\n */\n async fetch(url: URL, requestInit: FrameRequestInit = {}) {\n this.emitSync(EVENTS.FETCH_BEFORE, requestInit.trigger, url, requestInit);\n\n this.abortController.abort();\n this.abortController = new AbortController();\n const init = {\n ...this.requestInit,\n ...requestInit,\n headers: {\n ...this.requestInit.headers,\n ...requestInit.headers,\n },\n signal: this.abortController.signal,\n };\n\n this.$log('fetch', url, init);\n this.emitSync(EVENTS.FETCH, init.trigger, url, init);\n\n try {\n const content = await this.client(url, init).then((response) => response.text());\n this.emitSync(EVENTS.FETCH_AFTER, init.trigger, url, requestInit, content);\n this.content(url, init, content);\n } catch (error) {\n this.emitSync(EVENTS.FETCH_AFTER, init.trigger, url, requestInit, error);\n this.error(url, init, error);\n }\n }\n\n /**\n * Dispatch the contents to update to their matching FrameTarget.\n */\n async content(url: URL, requestInit: FrameRequestInit, content: string) {\n this.$log('content', url, content);\n this.emitSync(EVENTS.CONTENT, requestInit.trigger, url, requestInit, content);\n\n const doc = this.domParser.parseFromString(content, 'text/html');\n const el = doc.querySelector(`#${this.id}`) ?? doc;\n const promises = [];\n\n // @todo inject styles and scripts from new <head>\n if (this.$options.history) {\n if (requestInit?.headers?.[this.headerNames.X_TRIGGERED_BY] !== 'popstate') {\n historyPush({ path: url.pathname, search: url.searchParams });\n }\n domScheduler.write(() => {\n if (doc.title) document.title = doc.title;\n });\n }\n\n for (const frameTarget of this.getDirectChildren('FrameTarget')) {\n promises.push(frameTarget.updateContent(el.querySelector(`#${frameTarget.id}`)));\n }\n\n await Promise.all(promises);\n\n this.emitSync(EVENTS.CONTENT_AFTER, requestInit.trigger, url, requestInit, content);\n\n // We need to update the root instance to make sure newly inserted\n // components are correctly detected and mounted. This avoid having\n // to declare all potentials component as children of the Frame component.\n await this.$root.$update();\n }\n\n /**\n * Handle errors.\n */\n async error(url: URL, requestInit: FrameRequestInit, error: Error) {\n this.$log('error', url, requestInit, error);\n this.emitSync(EVENTS.ERROR, requestInit.trigger, url, requestInit, error);\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -25,7 +25,7 @@ export interface HoverableProps extends BaseProps {
25
25
  declare const Hoverable_base: import("@studiometa/js-toolkit").BaseDecorator<import("@studiometa/js-toolkit").RelativePointerInterface, Base<BaseProps>>;
26
26
  /**
27
27
  * Hoverable class.
28
- * @link https://ui.studiometa.dev/-/components/Hoverable/
28
+ * @link https://ui.studiometa.dev/components/Hoverable/
29
29
  */
30
30
  export declare class Hoverable<T extends BaseProps = BaseProps> extends Hoverable_base<T & HoverableProps> {
31
31
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/Hoverable/Hoverable.ts"],
4
- "sourcesContent": ["import { Base, withRelativePointer } from '@studiometa/js-toolkit';\nimport type { BaseConfig, BaseProps, PointerServiceProps } from '@studiometa/js-toolkit';\nimport { map, transform, damp, getOffsetSizes, clamp01 } from '@studiometa/js-toolkit/utils';\n\nexport interface HoverableProps extends BaseProps {\n $refs: {\n /**\n * Target element that will be moved on hover.\n */\n target: HTMLElement;\n };\n $options: {\n /**\n * A number between in the range `0\u20131` used to smoothen the transition between each position.\n */\n sensitivity: number;\n /**\n * Wether to reverse the movement of the target or not.\n */\n reversed: boolean;\n /**\n * Wether to stop moving the target when the mouse is not over the root element or not.\n */\n contained: boolean;\n };\n}\n\n/**\n * Hoverable class.\n * @link https://ui.studiometa.dev/-/components/Hoverable/\n */\nexport class Hoverable<T extends BaseProps = BaseProps> extends withRelativePointer(Base)<\n T & HoverableProps\n> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Hoverable',\n refs: ['target'],\n options: {\n sensitivity: {\n type: Number,\n default: 0.1,\n },\n reversed: Boolean,\n contained: Boolean,\n },\n };\n\n props = {\n x: 0,\n y: 0,\n dampedX: 0,\n dampedY: 0,\n };\n\n /**\n * The hoverable element, defaults to `this.$refs.target`.\n */\n get target(): HTMLElement {\n return this.$refs.target;\n }\n\n /**\n * The bouding element, defaults to `this.$el`.\n */\n get parent(): HTMLElement {\n return this.$el;\n }\n\n /**\n * The bounds values in which the target can move.\n */\n get bounds() {\n const targetSizes = getOffsetSizes(this.target);\n const parentSizes = getOffsetSizes(this.parent);\n const xMin = targetSizes.x - parentSizes.x;\n const yMin = targetSizes.y - parentSizes.y;\n const xMax = xMin + targetSizes.width - parentSizes.width;\n const yMax = yMin + targetSizes.height - parentSizes.height;\n\n return {\n yMin: yMin * -1,\n yMax: yMax * -1,\n xMin: xMin * -1,\n xMax: xMax * -1,\n };\n }\n\n /**\n * Update props when the mouse moves.\n */\n movedrelative({ progress }: PointerServiceProps) {\n const { bounds, props } = this;\n const { reversed, contained } = this.$options;\n const { x, y } = progress;\n\n // Stop updating when pointer is outside of the parent bounds\n if (contained && (y < 0 || x < 0 || y > 1 || x > 1)) {\n return;\n }\n\n const from = reversed ? 1 : 0;\n const to = reversed ? 0 : 1;\n\n props.y = map(clamp01(y), from, to, bounds.yMin, bounds.yMax);\n props.x = map(clamp01(x), from, to, bounds.xMin, bounds.xMax);\n }\n\n /**\n * Update target position on each frame.\n */\n ticked() {\n const { props, target } = this;\n const { sensitivity } = this.$options;\n props.dampedY = damp(props.y, props.dampedY, sensitivity);\n props.dampedX = damp(props.x, props.dampedX, sensitivity);\n\n return () => {\n transform(target, {\n y: props.dampedY,\n x: props.dampedX,\n });\n };\n }\n}\n"],
4
+ "sourcesContent": ["import { Base, withRelativePointer } from '@studiometa/js-toolkit';\nimport type { BaseConfig, BaseProps, PointerServiceProps } from '@studiometa/js-toolkit';\nimport { map, transform, damp, getOffsetSizes, clamp01 } from '@studiometa/js-toolkit/utils';\n\nexport interface HoverableProps extends BaseProps {\n $refs: {\n /**\n * Target element that will be moved on hover.\n */\n target: HTMLElement;\n };\n $options: {\n /**\n * A number between in the range `0\u20131` used to smoothen the transition between each position.\n */\n sensitivity: number;\n /**\n * Wether to reverse the movement of the target or not.\n */\n reversed: boolean;\n /**\n * Wether to stop moving the target when the mouse is not over the root element or not.\n */\n contained: boolean;\n };\n}\n\n/**\n * Hoverable class.\n * @link https://ui.studiometa.dev/components/Hoverable/\n */\nexport class Hoverable<T extends BaseProps = BaseProps> extends withRelativePointer(Base)<\n T & HoverableProps\n> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Hoverable',\n refs: ['target'],\n options: {\n sensitivity: {\n type: Number,\n default: 0.1,\n },\n reversed: Boolean,\n contained: Boolean,\n },\n };\n\n props = {\n x: 0,\n y: 0,\n dampedX: 0,\n dampedY: 0,\n };\n\n /**\n * The hoverable element, defaults to `this.$refs.target`.\n */\n get target(): HTMLElement {\n return this.$refs.target;\n }\n\n /**\n * The bouding element, defaults to `this.$el`.\n */\n get parent(): HTMLElement {\n return this.$el;\n }\n\n /**\n * The bounds values in which the target can move.\n */\n get bounds() {\n const targetSizes = getOffsetSizes(this.target);\n const parentSizes = getOffsetSizes(this.parent);\n const xMin = targetSizes.x - parentSizes.x;\n const yMin = targetSizes.y - parentSizes.y;\n const xMax = xMin + targetSizes.width - parentSizes.width;\n const yMax = yMin + targetSizes.height - parentSizes.height;\n\n return {\n yMin: yMin * -1,\n yMax: yMax * -1,\n xMin: xMin * -1,\n xMax: xMax * -1,\n };\n }\n\n /**\n * Update props when the mouse moves.\n */\n movedrelative({ progress }: PointerServiceProps) {\n const { bounds, props } = this;\n const { reversed, contained } = this.$options;\n const { x, y } = progress;\n\n // Stop updating when pointer is outside of the parent bounds\n if (contained && (y < 0 || x < 0 || y > 1 || x > 1)) {\n return;\n }\n\n const from = reversed ? 1 : 0;\n const to = reversed ? 0 : 1;\n\n props.y = map(clamp01(y), from, to, bounds.yMin, bounds.yMax);\n props.x = map(clamp01(x), from, to, bounds.xMin, bounds.xMax);\n }\n\n /**\n * Update target position on each frame.\n */\n ticked() {\n const { props, target } = this;\n const { sensitivity } = this.$options;\n props.dampedY = damp(props.y, props.dampedY, sensitivity);\n props.dampedX = damp(props.x, props.dampedX, sensitivity);\n\n return () => {\n transform(target, {\n y: props.dampedY,\n x: props.dampedX,\n });\n };\n }\n}\n"],
5
5
  "mappings": "AAAA,SAAS,MAAM,2BAA2B;AAE1C,SAAS,KAAK,WAAW,MAAM,gBAAgB,eAAe;AA6BvD,MAAM,kBAAmD,oBAAoB,IAAI,EAEtF;AAAA;AAAA;AAAA;AAAA,EAIA,OAAO,SAAqB;AAAA,IAC1B,MAAM;AAAA,IACN,MAAM,CAAC,QAAQ;AAAA,IACf,SAAS;AAAA,MACP,aAAa;AAAA,QACX,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,MACA,UAAU;AAAA,MACV,WAAW;AAAA,IACb;AAAA,EACF;AAAA,EAEA,QAAQ;AAAA,IACN,GAAG;AAAA,IACH,GAAG;AAAA,IACH,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAsB;AACxB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAsB;AACxB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAS;AACX,UAAM,cAAc,eAAe,KAAK,MAAM;AAC9C,UAAM,cAAc,eAAe,KAAK,MAAM;AAC9C,UAAM,OAAO,YAAY,IAAI,YAAY;AACzC,UAAM,OAAO,YAAY,IAAI,YAAY;AACzC,UAAM,OAAO,OAAO,YAAY,QAAQ,YAAY;AACpD,UAAM,OAAO,OAAO,YAAY,SAAS,YAAY;AAErD,WAAO;AAAA,MACL,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,IACf;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,EAAE,SAAS,GAAwB;AAC/C,UAAM,EAAE,QAAQ,MAAM,IAAI;AAC1B,UAAM,EAAE,UAAU,UAAU,IAAI,KAAK;AACrC,UAAM,EAAE,GAAG,EAAE,IAAI;AAGjB,QAAI,cAAc,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI;AACnD;AAAA,IACF;AAEA,UAAM,OAAO,WAAW,IAAI;AAC5B,UAAM,KAAK,WAAW,IAAI;AAE1B,UAAM,IAAI,IAAI,QAAQ,CAAC,GAAG,MAAM,IAAI,OAAO,MAAM,OAAO,IAAI;AAC5D,UAAM,IAAI,IAAI,QAAQ,CAAC,GAAG,MAAM,IAAI,OAAO,MAAM,OAAO,IAAI;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS;AACP,UAAM,EAAE,OAAO,OAAO,IAAI;AAC1B,UAAM,EAAE,YAAY,IAAI,KAAK;AAC7B,UAAM,UAAU,KAAK,MAAM,GAAG,MAAM,SAAS,WAAW;AACxD,UAAM,UAAU,KAAK,MAAM,GAAG,MAAM,SAAS,WAAW;AAExD,WAAO,MAAM;AACX,gBAAU,QAAQ;AAAA,QAChB,GAAG,MAAM;AAAA,QACT,GAAG,MAAM;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -13,7 +13,7 @@ export interface LargeTextProps extends BaseProps {
13
13
  declare const LargeText_base: import("@studiometa/js-toolkit").BaseDecorator<import("@studiometa/js-toolkit").WithMountWhenInViewInterface, Base<BaseProps>, import("@studiometa/js-toolkit").WithMountWhenInViewProps>;
14
14
  /**
15
15
  * LargeText class.
16
- * @link https://ui.studiometa.dev/-/components/LargeText/
16
+ * @link https://ui.studiometa.dev/components/LargeText/
17
17
  */
18
18
  export declare class LargeText<T extends BaseProps = BaseProps> extends LargeText_base<T & LargeTextProps> implements BaseInterface {
19
19
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/LargeText/LargeText.ts"],
4
- "sourcesContent": ["import { Base, withMountWhenInView } from '@studiometa/js-toolkit';\nimport type { BaseProps, BaseInterface, ScrollServiceProps } from '@studiometa/js-toolkit';\nimport { damp, clamp, transform } from '@studiometa/js-toolkit/utils';\n\nexport interface LargeTextProps extends BaseProps {\n $refs: {\n target: HTMLElement;\n };\n $options: {\n skew: boolean;\n sensitivity: number;\n skewSensitivity: number;\n };\n}\n\n/**\n * LargeText class.\n * @link https://ui.studiometa.dev/-/components/LargeText/\n */\nexport class LargeText<T extends BaseProps = BaseProps>\n extends withMountWhenInView(Base, { rootMargin: '50%' })<T & LargeTextProps>\n implements BaseInterface\n{\n /**\n * Config.\n */\n static config = {\n name: 'LargeText',\n refs: ['target'],\n options: {\n skew: Boolean,\n sensitivity: {\n type: Number,\n default: 1,\n },\n skewSensitivity: {\n type: Number,\n default: 1,\n },\n },\n };\n\n /**\n * Translate X.\n */\n x = 0;\n\n /**\n * Scroll delta Y.\n */\n deltaY = 0;\n\n /**\n * Transform values.\n */\n transform = {\n skewX: 0,\n x: 0,\n };\n\n /**\n * Target width.\n */\n width = 0;\n\n /**\n * Set width on mount.\n */\n mounted() {\n this.width = this.$refs.target.clientWidth;\n }\n\n /**\n * Set width on resize.\n */\n resized() {\n this.width = this.$refs.target.clientWidth;\n }\n\n /**\n * Update delta scroll on scroll.\n */\n scrolled(props: ScrollServiceProps) {\n this.deltaY = props.delta.y;\n }\n\n /**\n * Update values on raf.\n */\n ticked() {\n this.x -= (Math.abs(this.deltaY) + 1) * this.$options.sensitivity;\n\n this.transform.x = damp(this.x, this.transform.x, 0.25);\n\n if (this.$options.skew) {\n this.transform.skewX = damp(\n clamp(this.deltaY * -1, -50, 50) * this.$options.skewSensitivity,\n this.transform.skewX,\n 0.25,\n );\n }\n\n if (this.x <= this.width * -1) {\n this.x = 0;\n this.transform.x += this.width;\n } else if (this.$options.sensitivity < 0 && this.x >= this.width) {\n this.x = 0;\n this.transform.x -= this.width;\n }\n\n return () => {\n transform(this.$refs.target, this.transform);\n };\n }\n}\n"],
4
+ "sourcesContent": ["import { Base, withMountWhenInView } from '@studiometa/js-toolkit';\nimport type { BaseProps, BaseInterface, ScrollServiceProps } from '@studiometa/js-toolkit';\nimport { damp, clamp, transform } from '@studiometa/js-toolkit/utils';\n\nexport interface LargeTextProps extends BaseProps {\n $refs: {\n target: HTMLElement;\n };\n $options: {\n skew: boolean;\n sensitivity: number;\n skewSensitivity: number;\n };\n}\n\n/**\n * LargeText class.\n * @link https://ui.studiometa.dev/components/LargeText/\n */\nexport class LargeText<T extends BaseProps = BaseProps>\n extends withMountWhenInView(Base, { rootMargin: '50%' })<T & LargeTextProps>\n implements BaseInterface\n{\n /**\n * Config.\n */\n static config = {\n name: 'LargeText',\n refs: ['target'],\n options: {\n skew: Boolean,\n sensitivity: {\n type: Number,\n default: 1,\n },\n skewSensitivity: {\n type: Number,\n default: 1,\n },\n },\n };\n\n /**\n * Translate X.\n */\n x = 0;\n\n /**\n * Scroll delta Y.\n */\n deltaY = 0;\n\n /**\n * Transform values.\n */\n transform = {\n skewX: 0,\n x: 0,\n };\n\n /**\n * Target width.\n */\n width = 0;\n\n /**\n * Set width on mount.\n */\n mounted() {\n this.width = this.$refs.target.clientWidth;\n }\n\n /**\n * Set width on resize.\n */\n resized() {\n this.width = this.$refs.target.clientWidth;\n }\n\n /**\n * Update delta scroll on scroll.\n */\n scrolled(props: ScrollServiceProps) {\n this.deltaY = props.delta.y;\n }\n\n /**\n * Update values on raf.\n */\n ticked() {\n this.x -= (Math.abs(this.deltaY) + 1) * this.$options.sensitivity;\n\n this.transform.x = damp(this.x, this.transform.x, 0.25);\n\n if (this.$options.skew) {\n this.transform.skewX = damp(\n clamp(this.deltaY * -1, -50, 50) * this.$options.skewSensitivity,\n this.transform.skewX,\n 0.25,\n );\n }\n\n if (this.x <= this.width * -1) {\n this.x = 0;\n this.transform.x += this.width;\n } else if (this.$options.sensitivity < 0 && this.x >= this.width) {\n this.x = 0;\n this.transform.x -= this.width;\n }\n\n return () => {\n transform(this.$refs.target, this.transform);\n };\n }\n}\n"],
5
5
  "mappings": "AAAA,SAAS,MAAM,2BAA2B;AAE1C,SAAS,MAAM,OAAO,iBAAiB;AAiBhC,MAAM,kBACH,oBAAoB,MAAM,EAAE,YAAY,MAAM,CAAC,EAEzD;AAAA;AAAA;AAAA;AAAA,EAIE,OAAO,SAAS;AAAA,IACd,MAAM;AAAA,IACN,MAAM,CAAC,QAAQ;AAAA,IACf,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,QACX,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,MACA,iBAAiB;AAAA,QACf,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI;AAAA;AAAA;AAAA;AAAA,EAKJ,SAAS;AAAA;AAAA;AAAA;AAAA,EAKT,YAAY;AAAA,IACV,OAAO;AAAA,IACP,GAAG;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ;AAAA;AAAA;AAAA;AAAA,EAKR,UAAU;AACR,SAAK,QAAQ,KAAK,MAAM,OAAO;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AACR,SAAK,QAAQ,KAAK,MAAM,OAAO;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,OAA2B;AAClC,SAAK,SAAS,MAAM,MAAM;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS;AACP,SAAK,MAAM,KAAK,IAAI,KAAK,MAAM,IAAI,KAAK,KAAK,SAAS;AAEtD,SAAK,UAAU,IAAI,KAAK,KAAK,GAAG,KAAK,UAAU,GAAG,IAAI;AAEtD,QAAI,KAAK,SAAS,MAAM;AACtB,WAAK,UAAU,QAAQ;AAAA,QACrB,MAAM,KAAK,SAAS,IAAI,KAAK,EAAE,IAAI,KAAK,SAAS;AAAA,QACjD,KAAK,UAAU;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAEA,QAAI,KAAK,KAAK,KAAK,QAAQ,IAAI;AAC7B,WAAK,IAAI;AACT,WAAK,UAAU,KAAK,KAAK;AAAA,IAC3B,WAAW,KAAK,SAAS,cAAc,KAAK,KAAK,KAAK,KAAK,OAAO;AAChE,WAAK,IAAI;AACT,WAAK,UAAU,KAAK,KAAK;AAAA,IAC3B;AAEA,WAAO,MAAM;AACX,gBAAU,KAAK,MAAM,QAAQ,KAAK,SAAS;AAAA,IAC7C;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -12,7 +12,7 @@ export interface LazyIncludeProps extends BaseProps {
12
12
  }
13
13
  /**
14
14
  * LazyInclude class.
15
- * @link https://ui.studiometa.dev/-/components/LazyInclude/
15
+ * @link https://ui.studiometa.dev/components/LazyInclude/
16
16
  */
17
17
  export declare class LazyInclude<T extends BaseProps = BaseProps> extends Base<T & LazyIncludeProps> implements BaseInterface {
18
18
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/LazyInclude/LazyInclude.ts"],
4
- "sourcesContent": ["import { Base } from '@studiometa/js-toolkit';\nimport type { BaseProps, BaseInterface } from '@studiometa/js-toolkit';\n\nexport interface LazyIncludeProps extends BaseProps {\n $refs: {\n loading: HTMLElement;\n error: HTMLElement;\n };\n $options: {\n src: string;\n terminateOnLoad: boolean;\n };\n}\n\n/**\n * LazyInclude class.\n * @link https://ui.studiometa.dev/-/components/LazyInclude/\n */\nexport class LazyInclude<T extends BaseProps = BaseProps>\n extends Base<T & LazyIncludeProps>\n implements BaseInterface\n{\n /**\n * Config.\n */\n static config = {\n name: 'LazyInclude',\n refs: ['loading', 'error'],\n emits: ['content', 'error', 'always'],\n options: {\n src: String,\n terminateOnLoad: Boolean,\n },\n };\n\n /**\n * Load the lazy content on mount.\n */\n mounted() {\n if (!this.$options.src) {\n this.$warn('The `src` option is missing. Define it with the `data-option-src` attribute');\n return;\n }\n\n fetch(this.$options.src)\n .then((response) => response.text())\n .then((content) => {\n this.$emit('content', content);\n })\n .catch((error) => {\n this.$emit('error', error);\n })\n .finally(() => {\n this.$emit('always');\n });\n }\n\n /**\n * Set content.\n */\n onContent({ args: [content] }: { args: [string] }) {\n this.$refs.loading.style.display = 'none';\n this.$el.innerHTML = content;\n }\n\n /**\n * Set error.\n */\n onError() {\n this.$refs.error.style.display = 'block';\n }\n\n /**\n * Always.\n */\n onAlways() {\n if (this.$options.terminateOnLoad) {\n this.$terminate();\n }\n }\n}\n"],
4
+ "sourcesContent": ["import { Base } from '@studiometa/js-toolkit';\nimport type { BaseProps, BaseInterface } from '@studiometa/js-toolkit';\n\nexport interface LazyIncludeProps extends BaseProps {\n $refs: {\n loading: HTMLElement;\n error: HTMLElement;\n };\n $options: {\n src: string;\n terminateOnLoad: boolean;\n };\n}\n\n/**\n * LazyInclude class.\n * @link https://ui.studiometa.dev/components/LazyInclude/\n */\nexport class LazyInclude<T extends BaseProps = BaseProps>\n extends Base<T & LazyIncludeProps>\n implements BaseInterface\n{\n /**\n * Config.\n */\n static config = {\n name: 'LazyInclude',\n refs: ['loading', 'error'],\n emits: ['content', 'error', 'always'],\n options: {\n src: String,\n terminateOnLoad: Boolean,\n },\n };\n\n /**\n * Load the lazy content on mount.\n */\n mounted() {\n if (!this.$options.src) {\n this.$warn('The `src` option is missing. Define it with the `data-option-src` attribute');\n return;\n }\n\n fetch(this.$options.src)\n .then((response) => response.text())\n .then((content) => {\n this.$emit('content', content);\n })\n .catch((error) => {\n this.$emit('error', error);\n })\n .finally(() => {\n this.$emit('always');\n });\n }\n\n /**\n * Set content.\n */\n onContent({ args: [content] }: { args: [string] }) {\n this.$refs.loading.style.display = 'none';\n this.$el.innerHTML = content;\n }\n\n /**\n * Set error.\n */\n onError() {\n this.$refs.error.style.display = 'block';\n }\n\n /**\n * Always.\n */\n onAlways() {\n if (this.$options.terminateOnLoad) {\n this.$terminate();\n }\n }\n}\n"],
5
5
  "mappings": "AAAA,SAAS,YAAY;AAkBd,MAAM,oBACH,KAEV;AAAA;AAAA;AAAA;AAAA,EAIE,OAAO,SAAS;AAAA,IACd,MAAM;AAAA,IACN,MAAM,CAAC,WAAW,OAAO;AAAA,IACzB,OAAO,CAAC,WAAW,SAAS,QAAQ;AAAA,IACpC,SAAS;AAAA,MACP,KAAK;AAAA,MACL,iBAAiB;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AACR,QAAI,CAAC,KAAK,SAAS,KAAK;AACtB,WAAK,MAAM,6EAA6E;AACxF;AAAA,IACF;AAEA,UAAM,KAAK,SAAS,GAAG,EACpB,KAAK,CAAC,aAAa,SAAS,KAAK,CAAC,EAClC,KAAK,CAAC,YAAY;AACjB,WAAK,MAAM,WAAW,OAAO;AAAA,IAC/B,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,WAAK,MAAM,SAAS,KAAK;AAAA,IAC3B,CAAC,EACA,QAAQ,MAAM;AACb,WAAK,MAAM,QAAQ;AAAA,IACrB,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,EAAE,MAAM,CAAC,OAAO,EAAE,GAAuB;AACjD,SAAK,MAAM,QAAQ,MAAM,UAAU;AACnC,SAAK,IAAI,YAAY;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AACR,SAAK,MAAM,MAAM,MAAM,UAAU;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW;AACT,QAAI,KAAK,SAAS,iBAAiB;AACjC,WAAK,WAAW;AAAA,IAClB;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
package/Menu/Menu.d.ts CHANGED
@@ -14,7 +14,7 @@ export interface MenuProps extends BaseProps {
14
14
  }
15
15
  /**
16
16
  * Menu class.
17
- * @link https://ui.studiometa.dev/-/components/Menu/
17
+ * @link https://ui.studiometa.dev/components/Menu/
18
18
  */
19
19
  export declare class Menu<T extends BaseProps = BaseProps> extends Base<T & MenuProps> {
20
20
  /**
package/Menu/Menu.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/Menu/Menu.ts"],
4
- "sourcesContent": ["import { Base, getClosestParent } from '@studiometa/js-toolkit';\nimport type { BaseConfig, BaseProps, KeyServiceProps } from '@studiometa/js-toolkit';\nimport { nextTick } from '@studiometa/js-toolkit/utils';\nimport { MenuBtn } from './MenuBtn.js';\nimport { MenuList } from './MenuList.js';\n\nexport interface MenuProps extends BaseProps {\n $children: {\n // eslint-disable-next-line no-use-before-define\n Menu: Menu[];\n MenuBtn: MenuBtn[];\n MenuList: MenuList[];\n };\n $options: {\n mode: 'click' | 'hover';\n };\n}\n\n/**\n * Menu class.\n * @link https://ui.studiometa.dev/-/components/Menu/\n */\nexport class Menu<T extends BaseProps = BaseProps> extends Base<T & MenuProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Menu',\n components: {\n MenuBtn,\n MenuList,\n },\n options: {\n mode: {\n type: String,\n default: 'click', // or 'hover'\n },\n },\n };\n\n /**\n * Get the first `MenuList` instance.\n */\n get menuList(): MenuList {\n for (const menuList of this.$children.MenuList) {\n if (getClosestParent(menuList, this.constructor) === this) {\n return menuList;\n }\n }\n }\n\n /**\n * Get the first `MenuBtn` instance.\n */\n get menuBtn(): MenuBtn {\n for (const menuBtn of this.$children.MenuBtn) {\n if (getClosestParent(menuBtn, this.constructor) === this) {\n return menuBtn;\n }\n }\n }\n\n /**\n * Test which mode to use.\n */\n get shouldReactOnClick(): boolean {\n return this.$options.mode === 'click';\n }\n\n /**\n * Wether the button or the items are hovered.\n */\n get isHover(): boolean {\n return this.menuBtn.isHover || this.menuList.isHover;\n }\n\n /**\n * Set attributes on mounted, destroy the component if it is missing required\n * child components.\n */\n mounted() {\n if (!this.menuBtn || !this.menuList) {\n return this.$destroy();\n }\n\n this.menuBtn.$el.setAttribute('aria-controls', this.$id);\n this.menuList.$el.setAttribute('id', this.$id);\n this.menuList.close();\n }\n\n /**\n * Keyboard management.\n */\n keyed({ ENTER, ESC, isUp }: KeyServiceProps) {\n if (!isUp) {\n return;\n }\n\n if (ESC) {\n this.close();\n return;\n }\n\n if (!this.shouldReactOnClick) {\n const hasFocusElementWithin = document.activeElement === this.menuBtn.$el;\n\n if (ENTER && hasFocusElementWithin) {\n this.toggle();\n }\n }\n }\n\n /**\n * Close menu list on click outside.\n */\n onDocumentClick({ event }: { event: MouseEvent }) {\n if (this.shouldReactOnClick && !this.$el.contains(event.target as Node)) {\n this.close();\n }\n }\n\n /**\n * Toggle menu items on button click.\n */\n onMenuBtnClick({ event, target }: { event: MouseEvent; target: MenuBtn }) {\n if (!this.shouldReactOnClick) return;\n\n if (getClosestParent(target, this.constructor) === this) {\n event.preventDefault();\n this.toggle();\n }\n }\n\n /**\n * Open menu items on button mouse enter.\n */\n onMenuBtnMouseenter({ target }: { target: MenuBtn }) {\n if (target === this.menuBtn && !this.shouldReactOnClick) {\n this.open();\n }\n }\n\n /**\n * Close menu items on button mouse leave.\n */\n onMenuBtnMouseleave() {\n if (this.shouldReactOnClick) {\n return;\n }\n\n nextTick(() => {\n if (!this.isHover) {\n this.close();\n }\n });\n }\n\n /**\n * Close menu items on button mouse leave.\n */\n onMenuListMouseleave() {\n if (this.shouldReactOnClick) {\n return;\n }\n\n nextTick(() => {\n if (!this.isHover) {\n this.close();\n }\n });\n }\n\n /**\n * Close other non-parent menu items on menu items open.\n */\n onMenuListItemsOpen({ target }: { target: MenuList }) {\n for (const menuList of this.$children.MenuList) {\n if (!menuList.$el.contains(target.$el)) {\n menuList.close();\n }\n }\n }\n\n /**\n * Close the menu.\n */\n close() {\n this.menuList.close();\n }\n\n /**\n * Open the menu.\n */\n open() {\n this.menuList.open();\n }\n\n /**\n * Toggle the menu.\n */\n toggle() {\n this.menuList.toggle();\n }\n}\n"],
4
+ "sourcesContent": ["import { Base, getClosestParent } from '@studiometa/js-toolkit';\nimport type { BaseConfig, BaseProps, KeyServiceProps } from '@studiometa/js-toolkit';\nimport { nextTick } from '@studiometa/js-toolkit/utils';\nimport { MenuBtn } from './MenuBtn.js';\nimport { MenuList } from './MenuList.js';\n\nexport interface MenuProps extends BaseProps {\n $children: {\n // eslint-disable-next-line no-use-before-define\n Menu: Menu[];\n MenuBtn: MenuBtn[];\n MenuList: MenuList[];\n };\n $options: {\n mode: 'click' | 'hover';\n };\n}\n\n/**\n * Menu class.\n * @link https://ui.studiometa.dev/components/Menu/\n */\nexport class Menu<T extends BaseProps = BaseProps> extends Base<T & MenuProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Menu',\n components: {\n MenuBtn,\n MenuList,\n },\n options: {\n mode: {\n type: String,\n default: 'click', // or 'hover'\n },\n },\n };\n\n /**\n * Get the first `MenuList` instance.\n */\n get menuList(): MenuList {\n for (const menuList of this.$children.MenuList) {\n if (getClosestParent(menuList, this.constructor) === this) {\n return menuList;\n }\n }\n }\n\n /**\n * Get the first `MenuBtn` instance.\n */\n get menuBtn(): MenuBtn {\n for (const menuBtn of this.$children.MenuBtn) {\n if (getClosestParent(menuBtn, this.constructor) === this) {\n return menuBtn;\n }\n }\n }\n\n /**\n * Test which mode to use.\n */\n get shouldReactOnClick(): boolean {\n return this.$options.mode === 'click';\n }\n\n /**\n * Wether the button or the items are hovered.\n */\n get isHover(): boolean {\n return this.menuBtn.isHover || this.menuList.isHover;\n }\n\n /**\n * Set attributes on mounted, destroy the component if it is missing required\n * child components.\n */\n mounted() {\n if (!this.menuBtn || !this.menuList) {\n return this.$destroy();\n }\n\n this.menuBtn.$el.setAttribute('aria-controls', this.$id);\n this.menuList.$el.setAttribute('id', this.$id);\n this.menuList.close();\n }\n\n /**\n * Keyboard management.\n */\n keyed({ ENTER, ESC, isUp }: KeyServiceProps) {\n if (!isUp) {\n return;\n }\n\n if (ESC) {\n this.close();\n return;\n }\n\n if (!this.shouldReactOnClick) {\n const hasFocusElementWithin = document.activeElement === this.menuBtn.$el;\n\n if (ENTER && hasFocusElementWithin) {\n this.toggle();\n }\n }\n }\n\n /**\n * Close menu list on click outside.\n */\n onDocumentClick({ event }: { event: MouseEvent }) {\n if (this.shouldReactOnClick && !this.$el.contains(event.target as Node)) {\n this.close();\n }\n }\n\n /**\n * Toggle menu items on button click.\n */\n onMenuBtnClick({ event, target }: { event: MouseEvent; target: MenuBtn }) {\n if (!this.shouldReactOnClick) return;\n\n if (getClosestParent(target, this.constructor) === this) {\n event.preventDefault();\n this.toggle();\n }\n }\n\n /**\n * Open menu items on button mouse enter.\n */\n onMenuBtnMouseenter({ target }: { target: MenuBtn }) {\n if (target === this.menuBtn && !this.shouldReactOnClick) {\n this.open();\n }\n }\n\n /**\n * Close menu items on button mouse leave.\n */\n onMenuBtnMouseleave() {\n if (this.shouldReactOnClick) {\n return;\n }\n\n nextTick(() => {\n if (!this.isHover) {\n this.close();\n }\n });\n }\n\n /**\n * Close menu items on button mouse leave.\n */\n onMenuListMouseleave() {\n if (this.shouldReactOnClick) {\n return;\n }\n\n nextTick(() => {\n if (!this.isHover) {\n this.close();\n }\n });\n }\n\n /**\n * Close other non-parent menu items on menu items open.\n */\n onMenuListItemsOpen({ target }: { target: MenuList }) {\n for (const menuList of this.$children.MenuList) {\n if (!menuList.$el.contains(target.$el)) {\n menuList.close();\n }\n }\n }\n\n /**\n * Close the menu.\n */\n close() {\n this.menuList.close();\n }\n\n /**\n * Open the menu.\n */\n open() {\n this.menuList.open();\n }\n\n /**\n * Toggle the menu.\n */\n toggle() {\n this.menuList.toggle();\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
package/Menu/MenuList.js CHANGED
@@ -96,6 +96,7 @@ class MenuList extends Transition {
96
96
  /**
97
97
  * Toggle the menu items.
98
98
  */
99
+ // @ts-expect-error MenuList.toggle() must override Transition.toggle().
99
100
  toggle() {
100
101
  if (this.isOpen) {
101
102
  this.close();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/Menu/MenuList.ts"],
4
- "sourcesContent": ["import type { BaseConfig, BaseProps } from '@studiometa/js-toolkit';\nimport { getInstanceFromElement } from '@studiometa/js-toolkit';\nimport { Transition } from '../Transition/index.js';\n\nconst FOCUSABLE_ELEMENTS = [\n 'a[href]:not([inert])',\n 'area[href]:not([inert])',\n 'input:not([disabled]):not([inert])',\n 'select:not([disabled]):not([inert])',\n 'textarea:not([disabled]):not([inert])',\n 'button:not([disabled]):not([inert])',\n 'iframe:not([inert])',\n 'audio:not([inert])',\n 'video:not([inert])',\n '[contenteditable]:not([inert])',\n '[tabindex]:not([inert])',\n].join(',');\n\nexport interface MenuListProps extends BaseProps {\n $children: {\n // eslint-disable-next-line no-use-before-define\n MenuList: MenuList[];\n };\n}\n\n/**\n * MenuList class.\n */\nexport class MenuList<T extends BaseProps = BaseProps> extends Transition<T & MenuListProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n ...Transition.config,\n name: 'MenuList',\n emits: ['items-open', 'items-close', 'items-mouseleave'],\n components: {\n MenuList,\n },\n };\n\n /**\n * Are the menu items visible?\n */\n isOpen = false;\n\n /**\n * Wether the component is hovered.\n */\n isHover = false;\n\n /**\n * Override `Transition` options.\n */\n // @ts-ignore\n get $options() {\n const options = super.$options;\n\n options.leaveKeep = true;\n options.enterKeep = true;\n\n return options;\n }\n\n /**\n * Update tab indexes on mount.\n */\n mounted() {\n this.__updateTabIndexes('close');\n }\n\n /**\n * Set hover state.\n */\n onMouseenter() {\n this.isHover = true;\n }\n\n /**\n * Unset hover state.\n */\n onMouseleave() {\n this.isHover = false;\n }\n\n /**\n * Display the menu items.\n */\n open() {\n if (this.isOpen) {\n return;\n }\n\n this.__updateTabIndexes('open');\n this.$el.setAttribute('aria-hidden', 'false');\n this.isOpen = true;\n this.enter();\n this.$emit('items-open');\n }\n\n /**\n * Hide the menu items.\n */\n close() {\n if (!this.isOpen) {\n return;\n }\n\n // Close child menu items.\n for (const menuList of this.$children.MenuList) {\n menuList.close();\n }\n\n if (\n document.activeElement instanceof HTMLElement &&\n this.$el.contains(document.activeElement)\n ) {\n document.activeElement.blur();\n }\n\n this.$el.setAttribute('aria-hidden', 'true');\n this.__updateTabIndexes('close');\n this.isOpen = false;\n this.leave();\n this.$emit('items-close');\n }\n\n /**\n * Toggle the menu items.\n */\n toggle() {\n if (this.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * Update `tabindex` attribute of children focusable elements.\n * @private\n */\n __updateTabIndexes(mode: 'open' | 'close' = 'open') {\n for (const item of Array.from(this.$el.querySelectorAll(FOCUSABLE_ELEMENTS))) {\n if (this.__isFocusableElementFromThisMenuList(item as HTMLElement)) {\n if (mode === 'close') {\n item.setAttribute('tabindex', '-1');\n } else {\n item.removeAttribute('tabindex');\n }\n }\n }\n }\n\n /**\n * Filter out items which are inside a child `MenuList` instance.\n * @private\n */\n __isFocusableElementFromThisMenuList(item: HTMLElement): boolean {\n let ancestor = item.parentElement;\n let maybeInstance =null\n\n // @ts-ignore\n while (!maybeInstance) {\n maybeInstance = getInstanceFromElement(ancestor, this.constructor);\n ancestor = ancestor.parentElement;\n }\n\n return maybeInstance === this;\n }\n}\n"],
5
- "mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,kBAAkB;AAE3B,MAAM,qBAAqB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,GAAG;AAYH,MAAM,iBAAkD,WAA8B;AAAA;AAAA;AAAA;AAAA,EAI3F,OAAO,SAAqB;AAAA,IAC1B,GAAG,WAAW;AAAA,IACd,MAAM;AAAA,IACN,OAAO,CAAC,cAAc,eAAe,kBAAkB;AAAA,IACvD,YAAY;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS;AAAA;AAAA;AAAA;AAAA,EAKT,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,EAMV,IAAI,WAAW;AACb,UAAM,UAAU,MAAM;AAEtB,YAAQ,YAAY;AACpB,YAAQ,YAAY;AAEpB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AACR,SAAK,mBAAmB,OAAO;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe;AACb,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe;AACb,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO;AACL,QAAI,KAAK,QAAQ;AACf;AAAA,IACF;AAEA,SAAK,mBAAmB,MAAM;AAC9B,SAAK,IAAI,aAAa,eAAe,OAAO;AAC5C,SAAK,SAAS;AACd,SAAK,MAAM;AACX,SAAK,MAAM,YAAY;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ;AACN,QAAI,CAAC,KAAK,QAAQ;AAChB;AAAA,IACF;AAGA,eAAW,YAAY,KAAK,UAAU,UAAU;AAC9C,eAAS,MAAM;AAAA,IACjB;AAEA,QACE,SAAS,yBAAyB,eAClC,KAAK,IAAI,SAAS,SAAS,aAAa,GACxC;AACA,eAAS,cAAc,KAAK;AAAA,IAC9B;AAEA,SAAK,IAAI,aAAa,eAAe,MAAM;AAC3C,SAAK,mBAAmB,OAAO;AAC/B,SAAK,SAAS;AACd,SAAK,MAAM;AACX,SAAK,MAAM,aAAa;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS;AACP,QAAI,KAAK,QAAQ;AACf,WAAK,MAAM;AAAA,IACb,OAAO;AACL,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBAAmB,OAAyB,QAAQ;AAClD,eAAW,QAAQ,MAAM,KAAK,KAAK,IAAI,iBAAiB,kBAAkB,CAAC,GAAG;AAC5E,UAAI,KAAK,qCAAqC,IAAmB,GAAG;AAClE,YAAI,SAAS,SAAS;AACpB,eAAK,aAAa,YAAY,IAAI;AAAA,QACpC,OAAO;AACL,eAAK,gBAAgB,UAAU;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,qCAAqC,MAA4B;AAC/D,QAAI,WAAW,KAAK;AACpB,QAAI,gBAAe;AAGnB,WAAO,CAAC,eAAe;AACrB,sBAAgB,uBAAuB,UAAU,KAAK,WAAW;AACjE,iBAAW,SAAS;AAAA,IACtB;AAEA,WAAO,kBAAkB;AAAA,EAC3B;AACF;",
4
+ "sourcesContent": ["import type { BaseConfig, BaseProps } from '@studiometa/js-toolkit';\nimport { getInstanceFromElement } from '@studiometa/js-toolkit';\nimport { Transition } from '../Transition/index.js';\n\nconst FOCUSABLE_ELEMENTS = [\n 'a[href]:not([inert])',\n 'area[href]:not([inert])',\n 'input:not([disabled]):not([inert])',\n 'select:not([disabled]):not([inert])',\n 'textarea:not([disabled]):not([inert])',\n 'button:not([disabled]):not([inert])',\n 'iframe:not([inert])',\n 'audio:not([inert])',\n 'video:not([inert])',\n '[contenteditable]:not([inert])',\n '[tabindex]:not([inert])',\n].join(',');\n\nexport interface MenuListProps extends BaseProps {\n $children: {\n // eslint-disable-next-line no-use-before-define\n MenuList: MenuList[];\n };\n}\n\n/**\n * MenuList class.\n */\nexport class MenuList<T extends BaseProps = BaseProps> extends Transition<T & MenuListProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n ...Transition.config,\n name: 'MenuList',\n emits: ['items-open', 'items-close', 'items-mouseleave'],\n components: {\n MenuList,\n },\n };\n\n /**\n * Are the menu items visible?\n */\n isOpen = false;\n\n /**\n * Wether the component is hovered.\n */\n isHover = false;\n\n /**\n * Override `Transition` options.\n */\n // @ts-ignore\n get $options() {\n const options = super.$options;\n\n options.leaveKeep = true;\n options.enterKeep = true;\n\n return options;\n }\n\n /**\n * Update tab indexes on mount.\n */\n mounted() {\n this.__updateTabIndexes('close');\n }\n\n /**\n * Set hover state.\n */\n onMouseenter() {\n this.isHover = true;\n }\n\n /**\n * Unset hover state.\n */\n onMouseleave() {\n this.isHover = false;\n }\n\n /**\n * Display the menu items.\n */\n open() {\n if (this.isOpen) {\n return;\n }\n\n this.__updateTabIndexes('open');\n this.$el.setAttribute('aria-hidden', 'false');\n this.isOpen = true;\n this.enter();\n this.$emit('items-open');\n }\n\n /**\n * Hide the menu items.\n */\n close() {\n if (!this.isOpen) {\n return;\n }\n\n // Close child menu items.\n for (const menuList of this.$children.MenuList) {\n menuList.close();\n }\n\n if (\n document.activeElement instanceof HTMLElement &&\n this.$el.contains(document.activeElement)\n ) {\n document.activeElement.blur();\n }\n\n this.$el.setAttribute('aria-hidden', 'true');\n this.__updateTabIndexes('close');\n this.isOpen = false;\n this.leave();\n this.$emit('items-close');\n }\n\n /**\n * Toggle the menu items.\n */\n // @ts-expect-error MenuList.toggle() must override Transition.toggle().\n toggle() {\n if (this.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * Update `tabindex` attribute of children focusable elements.\n * @private\n */\n __updateTabIndexes(mode: 'open' | 'close' = 'open') {\n for (const item of Array.from(this.$el.querySelectorAll(FOCUSABLE_ELEMENTS))) {\n if (this.__isFocusableElementFromThisMenuList(item as HTMLElement)) {\n if (mode === 'close') {\n item.setAttribute('tabindex', '-1');\n } else {\n item.removeAttribute('tabindex');\n }\n }\n }\n }\n\n /**\n * Filter out items which are inside a child `MenuList` instance.\n * @private\n */\n __isFocusableElementFromThisMenuList(item: HTMLElement): boolean {\n let ancestor = item.parentElement;\n let maybeInstance =null\n\n // @ts-ignore\n while (!maybeInstance) {\n maybeInstance = getInstanceFromElement(ancestor, this.constructor);\n ancestor = ancestor.parentElement;\n }\n\n return maybeInstance === this;\n }\n}\n"],
5
+ "mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,kBAAkB;AAE3B,MAAM,qBAAqB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,GAAG;AAYH,MAAM,iBAAkD,WAA8B;AAAA;AAAA;AAAA;AAAA,EAI3F,OAAO,SAAqB;AAAA,IAC1B,GAAG,WAAW;AAAA,IACd,MAAM;AAAA,IACN,OAAO,CAAC,cAAc,eAAe,kBAAkB;AAAA,IACvD,YAAY;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS;AAAA;AAAA;AAAA;AAAA,EAKT,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,EAMV,IAAI,WAAW;AACb,UAAM,UAAU,MAAM;AAEtB,YAAQ,YAAY;AACpB,YAAQ,YAAY;AAEpB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AACR,SAAK,mBAAmB,OAAO;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe;AACb,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe;AACb,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO;AACL,QAAI,KAAK,QAAQ;AACf;AAAA,IACF;AAEA,SAAK,mBAAmB,MAAM;AAC9B,SAAK,IAAI,aAAa,eAAe,OAAO;AAC5C,SAAK,SAAS;AACd,SAAK,MAAM;AACX,SAAK,MAAM,YAAY;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ;AACN,QAAI,CAAC,KAAK,QAAQ;AAChB;AAAA,IACF;AAGA,eAAW,YAAY,KAAK,UAAU,UAAU;AAC9C,eAAS,MAAM;AAAA,IACjB;AAEA,QACE,SAAS,yBAAyB,eAClC,KAAK,IAAI,SAAS,SAAS,aAAa,GACxC;AACA,eAAS,cAAc,KAAK;AAAA,IAC9B;AAEA,SAAK,IAAI,aAAa,eAAe,MAAM;AAC3C,SAAK,mBAAmB,OAAO;AAC/B,SAAK,SAAS;AACd,SAAK,MAAM;AACX,SAAK,MAAM,aAAa;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS;AACP,QAAI,KAAK,QAAQ;AACf,WAAK,MAAM;AAAA,IACb,OAAO;AACL,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBAAmB,OAAyB,QAAQ;AAClD,eAAW,QAAQ,MAAM,KAAK,KAAK,IAAI,iBAAiB,kBAAkB,CAAC,GAAG;AAC5E,UAAI,KAAK,qCAAqC,IAAmB,GAAG;AAClE,YAAI,SAAS,SAAS;AACpB,eAAK,aAAa,YAAY,IAAI;AAAA,QACpC,OAAO;AACL,eAAK,gBAAgB,UAAU;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,qCAAqC,MAA4B;AAC/D,QAAI,WAAW,KAAK;AACpB,QAAI,gBAAe;AAGnB,WAAO,CAAC,eAAe;AACrB,sBAAgB,uBAAuB,UAAU,KAAK,WAAW;AACjE,iBAAW,SAAS;AAAA,IACtB;AAEA,WAAO,kBAAkB;AAAA,EAC3B;AACF;",
6
6
  "names": []
7
7
  }
package/Modal/Modal.d.ts CHANGED
@@ -32,7 +32,7 @@ export interface ModalProps extends BaseProps {
32
32
  }
33
33
  /**
34
34
  * Modal class.
35
- * @link https://ui.studiometa.dev/-/components/Modal/
35
+ * @link https://ui.studiometa.dev/components/Modal/
36
36
  */
37
37
  export declare class Modal<T extends BaseProps = BaseProps> extends Base<T & ModalProps> {
38
38
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/Modal/Modal.ts"],
4
- "sourcesContent": ["import { Base, KeyServiceProps } from '@studiometa/js-toolkit';\nimport type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';\nimport {\n transition,\n trapFocus as trap,\n untrapFocus as untrap,\n saveActiveElement,\n} from '@studiometa/js-toolkit/utils';\n\ntype ModalStates = Partial<\n Record<'open' | 'active' | 'closed', string | Partial<CSSStyleDeclaration>>\n>;\n// eslint-disable-next-line no-use-before-define\ntype ModalStylesOption = Partial<Record<keyof ModalProps['$refs'], ModalStates>>;\n\nexport interface ModalProps extends BaseProps {\n $refs: {\n close: HTMLElement[];\n container: HTMLElement;\n content: HTMLElement;\n modal: HTMLElement;\n open: HTMLElement[];\n overlay: HTMLElement;\n };\n $options: {\n /**\n * A selector where to move the modal to.\n */\n move: string;\n /**\n * A selector for the element to set the focus to when the modal opens.\n */\n autofocus: string;\n /**\n * Lock or allow scroll in the documentElement.\n */\n scrollLock: boolean;\n /**\n * The styles for the different state of the modal.\n */\n styles: ModalStylesOption;\n };\n}\n\n/**\n * Modal class.\n * @link https://ui.studiometa.dev/-/components/Modal/\n */\nexport class Modal<T extends BaseProps = BaseProps> extends Base<T & ModalProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Modal',\n refs: ['close[]', 'container', 'content', 'modal', 'open[]', 'overlay'],\n emits: ['open', 'close'],\n options: {\n move: String,\n autofocus: { type: String, default: '[autofocus]' },\n styles: {\n type: Object,\n default: (): ModalStylesOption => ({\n modal: {\n closed: {\n opacity: '0',\n pointerEvents: 'none',\n visibility: 'hidden',\n },\n },\n }),\n },\n scrollLock: {\n type: Boolean,\n default: true,\n },\n },\n };\n\n /**\n * Wether the modal is open or not.\n */\n isOpen = false;\n\n /**\n * @private\n */\n __refsBackup: (T & ModalProps)['$refs'];\n\n /**\n * @private\n */\n __refModalPlaceholder: Comment;\n\n /**\n * @private\n */\n __refModalParentBackup: HTMLElement;\n\n /**\n * @private\n */\n __refModalUnbindGetRefFilter: () => void;\n\n /**\n * Open the modal on click on the `open` ref.\n */\n get onOpenClick() {\n return this.open;\n }\n\n /**\n * Close the modal on click on the `close` ref.\n */\n get onCloseClick() {\n return this.close;\n }\n\n /**\n * Close the modal on click on the `overlay` ref.\n * @returns {Function} The component's `close` method.\n */\n get onOverlayClick() {\n return this.close;\n }\n\n /**\n * Initialize the component's behaviours.\n */\n mounted() {\n this.isOpen = false;\n this.close();\n\n if (this.$options.move) {\n const target = document.querySelector(this.$options.move) || document.body;\n\n this.__refsBackup = this.$refs;\n this.__refModalPlaceholder = document.createComment('');\n this.__refModalParentBackup = this.$refs.modal.parentElement || this.$el;\n this.__refModalParentBackup.insertBefore(this.__refModalPlaceholder, this.$refs.modal);\n\n target.append(this.$refs.modal);\n }\n }\n\n /**\n * Add the moved refs to `this.$refs` when using the `move` options.\n */\n get $refs() {\n const $refs = super.$refs;\n\n if (this.$options.move && this.__refsBackup) {\n Object.entries(this.__refsBackup).forEach(([key, ref]) => {\n if (!$refs[key]) {\n // @ts-ignore\n $refs[key] = ref;\n }\n });\n }\n\n return $refs;\n }\n\n /**\n * Unbind all events on destroy.\n */\n destroyed() {\n this.close();\n\n if (this.$options.move && this.__refModalParentBackup) {\n this.__refModalParentBackup.insertBefore(this.$refs.modal, this.__refModalPlaceholder);\n this.__refModalPlaceholder.remove();\n delete this.__refModalPlaceholder;\n delete this.__refModalParentBackup;\n }\n\n return this;\n }\n\n /**\n * Close the modal on `ESC` and trap the tabulation.\n */\n keyed({ event, isUp, isDown, ESC }: KeyServiceProps) {\n if (!this.isOpen) {\n return;\n }\n\n if (isDown) {\n trap(this.$refs.modal, event);\n }\n\n if (ESC && isUp) {\n this.close();\n }\n }\n\n /**\n * Open the modal.\n */\n async open() {\n if (this.isOpen) {\n return Promise.resolve();\n }\n\n this.$refs.modal.setAttribute('aria-hidden', 'false');\n\n if (this.$options.scrollLock) {\n document.documentElement.style.overflow = 'hidden';\n }\n\n this.isOpen = true;\n this.$emit('open');\n\n /** @type {ModalRefs} */\n const refs = this.$refs;\n\n return Promise.all(\n Object.entries(this.$options.styles).map(\n ([refName, { open, active, closed } = { open: '', active: '', closed: '' }]) =>\n transition(\n refs[refName],\n {\n from: closed,\n active,\n to: open,\n },\n 'keep',\n ),\n ),\n ).then(() => {\n if (this.$options.autofocus && this.$refs.modal.querySelector(this.$options.autofocus)) {\n saveActiveElement();\n const autofocusElement = this.$refs.modal.querySelector(\n this.$options.autofocus,\n ) as HTMLElement;\n autofocusElement.focus();\n }\n return Promise.resolve();\n });\n }\n\n /**\n * Close the modal.\n */\n async close() {\n if (!this.isOpen) {\n return Promise.resolve();\n }\n\n this.$refs.modal.setAttribute('aria-hidden', 'true');\n\n if (this.$options.scrollLock) {\n document.documentElement.style.overflow = '';\n }\n\n this.isOpen = false;\n untrap();\n this.$emit('close');\n\n const refs = this.$refs;\n\n return Promise.all(\n Object.entries(this.$options.styles).map(\n ([refName, { open, active, closed } = { open: '', active: '', closed: '' }]) =>\n transition(\n refs[refName],\n {\n from: open,\n active,\n to: closed,\n },\n 'keep',\n ),\n ),\n ).then(() => Promise.resolve());\n }\n}\n"],
4
+ "sourcesContent": ["import { Base, KeyServiceProps } from '@studiometa/js-toolkit';\nimport type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';\nimport {\n transition,\n trapFocus as trap,\n untrapFocus as untrap,\n saveActiveElement,\n} from '@studiometa/js-toolkit/utils';\n\ntype ModalStates = Partial<\n Record<'open' | 'active' | 'closed', string | Partial<CSSStyleDeclaration>>\n>;\n// eslint-disable-next-line no-use-before-define\ntype ModalStylesOption = Partial<Record<keyof ModalProps['$refs'], ModalStates>>;\n\nexport interface ModalProps extends BaseProps {\n $refs: {\n close: HTMLElement[];\n container: HTMLElement;\n content: HTMLElement;\n modal: HTMLElement;\n open: HTMLElement[];\n overlay: HTMLElement;\n };\n $options: {\n /**\n * A selector where to move the modal to.\n */\n move: string;\n /**\n * A selector for the element to set the focus to when the modal opens.\n */\n autofocus: string;\n /**\n * Lock or allow scroll in the documentElement.\n */\n scrollLock: boolean;\n /**\n * The styles for the different state of the modal.\n */\n styles: ModalStylesOption;\n };\n}\n\n/**\n * Modal class.\n * @link https://ui.studiometa.dev/components/Modal/\n */\nexport class Modal<T extends BaseProps = BaseProps> extends Base<T & ModalProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Modal',\n refs: ['close[]', 'container', 'content', 'modal', 'open[]', 'overlay'],\n emits: ['open', 'close'],\n options: {\n move: String,\n autofocus: { type: String, default: '[autofocus]' },\n styles: {\n type: Object,\n default: (): ModalStylesOption => ({\n modal: {\n closed: {\n opacity: '0',\n pointerEvents: 'none',\n visibility: 'hidden',\n },\n },\n }),\n },\n scrollLock: {\n type: Boolean,\n default: true,\n },\n },\n };\n\n /**\n * Wether the modal is open or not.\n */\n isOpen = false;\n\n /**\n * @private\n */\n __refsBackup: (T & ModalProps)['$refs'];\n\n /**\n * @private\n */\n __refModalPlaceholder: Comment;\n\n /**\n * @private\n */\n __refModalParentBackup: HTMLElement;\n\n /**\n * @private\n */\n __refModalUnbindGetRefFilter: () => void;\n\n /**\n * Open the modal on click on the `open` ref.\n */\n get onOpenClick() {\n return this.open;\n }\n\n /**\n * Close the modal on click on the `close` ref.\n */\n get onCloseClick() {\n return this.close;\n }\n\n /**\n * Close the modal on click on the `overlay` ref.\n * @returns {Function} The component's `close` method.\n */\n get onOverlayClick() {\n return this.close;\n }\n\n /**\n * Initialize the component's behaviours.\n */\n mounted() {\n this.isOpen = false;\n this.close();\n\n if (this.$options.move) {\n const target = document.querySelector(this.$options.move) || document.body;\n\n this.__refsBackup = this.$refs;\n this.__refModalPlaceholder = document.createComment('');\n this.__refModalParentBackup = this.$refs.modal.parentElement || this.$el;\n this.__refModalParentBackup.insertBefore(this.__refModalPlaceholder, this.$refs.modal);\n\n target.append(this.$refs.modal);\n }\n }\n\n /**\n * Add the moved refs to `this.$refs` when using the `move` options.\n */\n get $refs() {\n const $refs = super.$refs;\n\n if (this.$options.move && this.__refsBackup) {\n Object.entries(this.__refsBackup).forEach(([key, ref]) => {\n if (!$refs[key]) {\n // @ts-ignore\n $refs[key] = ref;\n }\n });\n }\n\n return $refs;\n }\n\n /**\n * Unbind all events on destroy.\n */\n destroyed() {\n this.close();\n\n if (this.$options.move && this.__refModalParentBackup) {\n this.__refModalParentBackup.insertBefore(this.$refs.modal, this.__refModalPlaceholder);\n this.__refModalPlaceholder.remove();\n delete this.__refModalPlaceholder;\n delete this.__refModalParentBackup;\n }\n\n return this;\n }\n\n /**\n * Close the modal on `ESC` and trap the tabulation.\n */\n keyed({ event, isUp, isDown, ESC }: KeyServiceProps) {\n if (!this.isOpen) {\n return;\n }\n\n if (isDown) {\n trap(this.$refs.modal, event);\n }\n\n if (ESC && isUp) {\n this.close();\n }\n }\n\n /**\n * Open the modal.\n */\n async open() {\n if (this.isOpen) {\n return Promise.resolve();\n }\n\n this.$refs.modal.setAttribute('aria-hidden', 'false');\n\n if (this.$options.scrollLock) {\n document.documentElement.style.overflow = 'hidden';\n }\n\n this.isOpen = true;\n this.$emit('open');\n\n /** @type {ModalRefs} */\n const refs = this.$refs;\n\n return Promise.all(\n Object.entries(this.$options.styles).map(\n ([refName, { open, active, closed } = { open: '', active: '', closed: '' }]) =>\n transition(\n refs[refName],\n {\n from: closed,\n active,\n to: open,\n },\n 'keep',\n ),\n ),\n ).then(() => {\n if (this.$options.autofocus && this.$refs.modal.querySelector(this.$options.autofocus)) {\n saveActiveElement();\n const autofocusElement = this.$refs.modal.querySelector(\n this.$options.autofocus,\n ) as HTMLElement;\n autofocusElement.focus();\n }\n return Promise.resolve();\n });\n }\n\n /**\n * Close the modal.\n */\n async close() {\n if (!this.isOpen) {\n return Promise.resolve();\n }\n\n this.$refs.modal.setAttribute('aria-hidden', 'true');\n\n if (this.$options.scrollLock) {\n document.documentElement.style.overflow = '';\n }\n\n this.isOpen = false;\n untrap();\n this.$emit('close');\n\n const refs = this.$refs;\n\n return Promise.all(\n Object.entries(this.$options.styles).map(\n ([refName, { open, active, closed } = { open: '', active: '', closed: '' }]) =>\n transition(\n refs[refName],\n {\n from: open,\n active,\n to: closed,\n },\n 'keep',\n ),\n ),\n ).then(() => Promise.resolve());\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
package/Panel/Panel.d.ts CHANGED
@@ -7,7 +7,7 @@ export interface PanelProps extends BaseProps {
7
7
  }
8
8
  /**
9
9
  * Panel class.
10
- * @link https://ui.studiometa.dev/-/components/Panel/
10
+ * @link https://ui.studiometa.dev/components/Panel/
11
11
  */
12
12
  export declare class Panel<T extends BaseProps = BaseProps> extends Modal<T & PanelProps> {
13
13
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/Panel/Panel.ts"],
4
- "sourcesContent": ["import type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';\nimport { transition, matrix } from '@studiometa/js-toolkit/utils';\nimport { Modal } from '../Modal/index.js';\n\nexport interface PanelProps extends BaseProps {\n $options: {\n position: 'top' | 'right' | 'bottom' | 'left';\n };\n}\n\nconst DEFAULT_POSITION = 'left';\n\n/**\n * Panel class.\n * @link https://ui.studiometa.dev/-/components/Panel/\n */\nexport class Panel<T extends BaseProps = BaseProps> extends Modal<T & PanelProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Panel',\n options: {\n position: {\n type: String,\n default: DEFAULT_POSITION,\n },\n },\n };\n\n static translateClasses = {\n top: '-translate-y-full',\n right: 'translate-x-full',\n bottom: 'translate-y-full',\n left: '-translate-x-full',\n };\n\n isClosing = false;\n\n /**\n * Get the translation class.\n * @returns {string}\n */\n get translateClass() {\n return (\n Panel.translateClasses[this.$options.position] ?? Panel.translateClasses[DEFAULT_POSITION]\n );\n }\n\n get containerOffset() {\n const { offsetTop, offsetLeft, offsetWidth, offsetHeight } = this.$refs.container;\n\n const store = {\n top: {\n translateY: (offsetTop + offsetHeight) * -1,\n },\n right: {\n translateX: window.innerWidth - offsetLeft + offsetWidth * 2,\n },\n bottom: {\n translateY: window.innerHeight - offsetTop + offsetHeight * 2,\n },\n left: {\n translateX: (offsetLeft + offsetWidth) * -1,\n },\n };\n\n return matrix(store[this.$options.position]);\n }\n\n /**\n * Animate before opening.\n * @this {PanelInterface}\n * @returns {Promise<void>}\n */\n async open() {\n if (this.isOpen) {\n return Promise.resolve();\n }\n\n this.$refs.modal.classList.remove('pointer-events-none');\n transition(\n this.$refs.container,\n {\n from: {\n transform: this.containerOffset,\n },\n to: {\n transform: 'none',\n translate: 'none',\n },\n },\n 'keep',\n );\n transition(this.$refs.overlay, {\n from: 'opacity-0',\n });\n\n return super.open();\n }\n\n /**\n * Animate before closing.\n * @this {PanelInterface}\n * @returns {Promise<void>}\n */\n async close() {\n if (!this.isOpen || this.isClosing) {\n return Promise.resolve();\n }\n\n this.isClosing = true;\n\n this.$refs.modal.classList.add('pointer-events-none');\n await Promise.all([\n transition(\n this.$refs.container,\n {\n from: {\n transform: 'none',\n translate: 'none',\n },\n to: {\n transform: this.containerOffset,\n },\n },\n 'keep',\n ),\n transition(\n this.$refs.overlay,\n {\n to: 'opacity-0',\n },\n 'keep',\n ),\n ]);\n\n this.isClosing = false;\n\n return super.close();\n }\n}\n"],
4
+ "sourcesContent": ["import type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';\nimport { transition, matrix } from '@studiometa/js-toolkit/utils';\nimport { Modal } from '../Modal/index.js';\n\nexport interface PanelProps extends BaseProps {\n $options: {\n position: 'top' | 'right' | 'bottom' | 'left';\n };\n}\n\nconst DEFAULT_POSITION = 'left';\n\n/**\n * Panel class.\n * @link https://ui.studiometa.dev/components/Panel/\n */\nexport class Panel<T extends BaseProps = BaseProps> extends Modal<T & PanelProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Panel',\n options: {\n position: {\n type: String,\n default: DEFAULT_POSITION,\n },\n },\n };\n\n static translateClasses = {\n top: '-translate-y-full',\n right: 'translate-x-full',\n bottom: 'translate-y-full',\n left: '-translate-x-full',\n };\n\n isClosing = false;\n\n /**\n * Get the translation class.\n * @returns {string}\n */\n get translateClass() {\n return (\n Panel.translateClasses[this.$options.position] ?? Panel.translateClasses[DEFAULT_POSITION]\n );\n }\n\n get containerOffset() {\n const { offsetTop, offsetLeft, offsetWidth, offsetHeight } = this.$refs.container;\n\n const store = {\n top: {\n translateY: (offsetTop + offsetHeight) * -1,\n },\n right: {\n translateX: window.innerWidth - offsetLeft + offsetWidth * 2,\n },\n bottom: {\n translateY: window.innerHeight - offsetTop + offsetHeight * 2,\n },\n left: {\n translateX: (offsetLeft + offsetWidth) * -1,\n },\n };\n\n return matrix(store[this.$options.position]);\n }\n\n /**\n * Animate before opening.\n * @this {PanelInterface}\n * @returns {Promise<void>}\n */\n async open() {\n if (this.isOpen) {\n return Promise.resolve();\n }\n\n this.$refs.modal.classList.remove('pointer-events-none');\n transition(\n this.$refs.container,\n {\n from: {\n transform: this.containerOffset,\n },\n to: {\n transform: 'none',\n translate: 'none',\n },\n },\n 'keep',\n );\n transition(this.$refs.overlay, {\n from: 'opacity-0',\n });\n\n return super.open();\n }\n\n /**\n * Animate before closing.\n * @this {PanelInterface}\n * @returns {Promise<void>}\n */\n async close() {\n if (!this.isOpen || this.isClosing) {\n return Promise.resolve();\n }\n\n this.isClosing = true;\n\n this.$refs.modal.classList.add('pointer-events-none');\n await Promise.all([\n transition(\n this.$refs.container,\n {\n from: {\n transform: 'none',\n translate: 'none',\n },\n to: {\n transform: this.containerOffset,\n },\n },\n 'keep',\n ),\n transition(\n this.$refs.overlay,\n {\n to: 'opacity-0',\n },\n 'keep',\n ),\n ]);\n\n this.isClosing = false;\n\n return super.close();\n }\n}\n"],
5
5
  "mappings": "AACA,SAAS,YAAY,cAAc;AACnC,SAAS,aAAa;AAQtB,MAAM,mBAAmB;AAMlB,MAAM,cAA+C,MAAsB;AAAA;AAAA;AAAA;AAAA,EAIhF,OAAO,SAAqB;AAAA,IAC1B,MAAM;AAAA,IACN,SAAS;AAAA,MACP,UAAU;AAAA,QACR,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAO,mBAAmB;AAAA,IACxB,KAAK;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,MAAM;AAAA,EACR;AAAA,EAEA,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,EAMZ,IAAI,iBAAiB;AACnB,WACE,MAAM,iBAAiB,KAAK,SAAS,QAAQ,KAAK,MAAM,iBAAiB,gBAAgB;AAAA,EAE7F;AAAA,EAEA,IAAI,kBAAkB;AACpB,UAAM,EAAE,WAAW,YAAY,aAAa,aAAa,IAAI,KAAK,MAAM;AAExE,UAAM,QAAQ;AAAA,MACZ,KAAK;AAAA,QACH,aAAa,YAAY,gBAAgB;AAAA,MAC3C;AAAA,MACA,OAAO;AAAA,QACL,YAAY,OAAO,aAAa,aAAa,cAAc;AAAA,MAC7D;AAAA,MACA,QAAQ;AAAA,QACN,YAAY,OAAO,cAAc,YAAY,eAAe;AAAA,MAC9D;AAAA,MACA,MAAM;AAAA,QACJ,aAAa,aAAa,eAAe;AAAA,MAC3C;AAAA,IACF;AAEA,WAAO,OAAO,MAAM,KAAK,SAAS,QAAQ,CAAC;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAAO;AACX,QAAI,KAAK,QAAQ;AACf,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAEA,SAAK,MAAM,MAAM,UAAU,OAAO,qBAAqB;AACvD;AAAA,MACE,KAAK,MAAM;AAAA,MACX;AAAA,QACE,MAAM;AAAA,UACJ,WAAW,KAAK;AAAA,QAClB;AAAA,QACA,IAAI;AAAA,UACF,WAAW;AAAA,UACX,WAAW;AAAA,QACb;AAAA,MACF;AAAA,MACA;AAAA,IACF;AACA,eAAW,KAAK,MAAM,SAAS;AAAA,MAC7B,MAAM;AAAA,IACR,CAAC;AAED,WAAO,MAAM,KAAK;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAQ;AACZ,QAAI,CAAC,KAAK,UAAU,KAAK,WAAW;AAClC,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAEA,SAAK,YAAY;AAEjB,SAAK,MAAM,MAAM,UAAU,IAAI,qBAAqB;AACpD,UAAM,QAAQ,IAAI;AAAA,MAChB;AAAA,QACE,KAAK,MAAM;AAAA,QACX;AAAA,UACE,MAAM;AAAA,YACJ,WAAW;AAAA,YACX,WAAW;AAAA,UACb;AAAA,UACA,IAAI;AAAA,YACF,WAAW,KAAK;AAAA,UAClB;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,QACE,KAAK,MAAM;AAAA,QACX;AAAA,UACE,IAAI;AAAA,QACN;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAED,SAAK,YAAY;AAEjB,WAAO,MAAM,MAAM;AAAA,EACrB;AACF;",
6
6
  "names": []
7
7
  }
@@ -8,7 +8,7 @@ export interface AbstractPrefetchProps extends BaseProps {
8
8
  }
9
9
  /**
10
10
  * AbstractPrefetch class.
11
- * @link https://ui.studiometa.dev/-/components/Prefetch/
11
+ * @link https://ui.studiometa.dev/components/Prefetch/
12
12
  */
13
13
  export declare class AbstractPrefetch<T extends BaseProps = BaseProps> extends Base<T & AbstractPrefetchProps> {
14
14
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/Prefetch/AbstractPrefetch.ts"],
4
- "sourcesContent": ["import { Base } from '@studiometa/js-toolkit';\nimport type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';\n\nexport interface AbstractPrefetchProps extends BaseProps {\n $el: HTMLAnchorElement;\n $options: {\n prefetch: boolean;\n };\n}\n\n/**\n * AbstractPrefetch class.\n * @link https://ui.studiometa.dev/-/components/Prefetch/\n */\nexport class AbstractPrefetch<T extends BaseProps = BaseProps> extends Base<\n T & AbstractPrefetchProps\n> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'AbstractPrefetch',\n emits: ['prefetched'],\n options: {\n prefetch: {\n type: Boolean,\n default: true,\n },\n },\n };\n\n /**\n * Store prefetched URL.\n */\n static prefetchedUrls: Set<string> = new Set();\n\n /**\n * Get the URL to prefetch.\n */\n get url(): URL | null {\n const { href } = this.$el;\n return href ? new URL(href) : null;\n }\n\n /**\n * Is the URL prefetchable?\n */\n get isPrefetchable(): boolean {\n const { url } = this;\n\n if (!url || !url.href) {\n return false;\n }\n\n if (!this.$options.prefetch) {\n return false;\n }\n\n if (url.origin !== window.location.origin) {\n return false;\n }\n\n if (url.href === window.location.href) {\n return false;\n }\n\n if (\n url.hash &&\n url.pathname + url.search === window.location.pathname + window.location.search\n ) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Prefetch the URL.\n */\n prefetch() {\n const { url } = this;\n\n if (AbstractPrefetch.prefetchedUrls.has(url.href)) {\n return;\n }\n\n if (!this.isPrefetchable) {\n return;\n }\n\n const prefetcher = document.createElement('link');\n prefetcher.rel = 'prefetch';\n prefetcher.href = url.href;\n prefetcher.addEventListener('load', () => this.$emit('prefetched', url));\n document.head.append(prefetcher);\n\n AbstractPrefetch.prefetchedUrls.add(url.href);\n }\n}\n"],
4
+ "sourcesContent": ["import { Base } from '@studiometa/js-toolkit';\nimport type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';\n\nexport interface AbstractPrefetchProps extends BaseProps {\n $el: HTMLAnchorElement;\n $options: {\n prefetch: boolean;\n };\n}\n\n/**\n * AbstractPrefetch class.\n * @link https://ui.studiometa.dev/components/Prefetch/\n */\nexport class AbstractPrefetch<T extends BaseProps = BaseProps> extends Base<\n T & AbstractPrefetchProps\n> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'AbstractPrefetch',\n emits: ['prefetched'],\n options: {\n prefetch: {\n type: Boolean,\n default: true,\n },\n },\n };\n\n /**\n * Store prefetched URL.\n */\n static prefetchedUrls: Set<string> = new Set();\n\n /**\n * Get the URL to prefetch.\n */\n get url(): URL | null {\n const { href } = this.$el;\n return href ? new URL(href) : null;\n }\n\n /**\n * Is the URL prefetchable?\n */\n get isPrefetchable(): boolean {\n const { url } = this;\n\n if (!url || !url.href) {\n return false;\n }\n\n if (!this.$options.prefetch) {\n return false;\n }\n\n if (url.origin !== window.location.origin) {\n return false;\n }\n\n if (url.href === window.location.href) {\n return false;\n }\n\n if (\n url.hash &&\n url.pathname + url.search === window.location.pathname + window.location.search\n ) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Prefetch the URL.\n */\n prefetch() {\n const { url } = this;\n\n if (AbstractPrefetch.prefetchedUrls.has(url.href)) {\n return;\n }\n\n if (!this.isPrefetchable) {\n return;\n }\n\n const prefetcher = document.createElement('link');\n prefetcher.rel = 'prefetch';\n prefetcher.href = url.href;\n prefetcher.addEventListener('load', () => this.$emit('prefetched', url));\n document.head.append(prefetcher);\n\n AbstractPrefetch.prefetchedUrls.add(url.href);\n }\n}\n"],
5
5
  "mappings": "AAAA,SAAS,YAAY;AAcd,MAAM,yBAA0D,KAErE;AAAA;AAAA;AAAA;AAAA,EAIA,OAAO,SAAqB;AAAA,IAC1B,MAAM;AAAA,IACN,OAAO,CAAC,YAAY;AAAA,IACpB,SAAS;AAAA,MACP,UAAU;AAAA,QACR,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,iBAA8B,oBAAI,IAAI;AAAA;AAAA;AAAA;AAAA,EAK7C,IAAI,MAAkB;AACpB,UAAM,EAAE,KAAK,IAAI,KAAK;AACtB,WAAO,OAAO,IAAI,IAAI,IAAI,IAAI;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,iBAA0B;AAC5B,UAAM,EAAE,IAAI,IAAI;AAEhB,QAAI,CAAC,OAAO,CAAC,IAAI,MAAM;AACrB,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,KAAK,SAAS,UAAU;AAC3B,aAAO;AAAA,IACT;AAEA,QAAI,IAAI,WAAW,OAAO,SAAS,QAAQ;AACzC,aAAO;AAAA,IACT;AAEA,QAAI,IAAI,SAAS,OAAO,SAAS,MAAM;AACrC,aAAO;AAAA,IACT;AAEA,QACE,IAAI,QACJ,IAAI,WAAW,IAAI,WAAW,OAAO,SAAS,WAAW,OAAO,SAAS,QACzE;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW;AACT,UAAM,EAAE,IAAI,IAAI;AAEhB,QAAI,iBAAiB,eAAe,IAAI,IAAI,IAAI,GAAG;AACjD;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,gBAAgB;AACxB;AAAA,IACF;AAEA,UAAM,aAAa,SAAS,cAAc,MAAM;AAChD,eAAW,MAAM;AACjB,eAAW,OAAO,IAAI;AACtB,eAAW,iBAAiB,QAAQ,MAAM,KAAK,MAAM,cAAc,GAAG,CAAC;AACvE,aAAS,KAAK,OAAO,UAAU;AAE/B,qBAAiB,eAAe,IAAI,IAAI,IAAI;AAAA,EAC9C;AACF;",
6
6
  "names": []
7
7
  }
@@ -2,7 +2,7 @@ import type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';
2
2
  import { AbstractPrefetch } from './AbstractPrefetch.js';
3
3
  /**
4
4
  * PrefetchWhenOver class.
5
- * @link https://ui.studiometa.dev/-/components/Prefetch/
5
+ * @link https://ui.studiometa.dev/components/Prefetch/
6
6
  */
7
7
  export declare class PrefetchWhenOver<T extends BaseProps = BaseProps> extends AbstractPrefetch<T> {
8
8
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/Prefetch/PrefetchWhenOver.ts"],
4
- "sourcesContent": ["import type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';\nimport { AbstractPrefetch } from './AbstractPrefetch.js';\n\n/**\n * PrefetchWhenOver class.\n * @link https://ui.studiometa.dev/-/components/Prefetch/\n */\nexport class PrefetchWhenOver<T extends BaseProps = BaseProps> extends AbstractPrefetch<T> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n ...AbstractPrefetch.config,\n name: 'PrefetchWhenOver',\n };\n\n /**\n * Prefetch on mouseenter.\n */\n onMouseenter() {\n this.prefetch();\n }\n}\n"],
4
+ "sourcesContent": ["import type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';\nimport { AbstractPrefetch } from './AbstractPrefetch.js';\n\n/**\n * PrefetchWhenOver class.\n * @link https://ui.studiometa.dev/components/Prefetch/\n */\nexport class PrefetchWhenOver<T extends BaseProps = BaseProps> extends AbstractPrefetch<T> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n ...AbstractPrefetch.config,\n name: 'PrefetchWhenOver',\n };\n\n /**\n * Prefetch on mouseenter.\n */\n onMouseenter() {\n this.prefetch();\n }\n}\n"],
5
5
  "mappings": "AACA,SAAS,wBAAwB;AAM1B,MAAM,yBAA0D,iBAAoB;AAAA;AAAA;AAAA;AAAA,EAIzF,OAAO,SAAqB;AAAA,IAC1B,GAAG,iBAAiB;AAAA,IACpB,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe;AACb,SAAK,SAAS;AAAA,EAChB;AACF;",
6
6
  "names": []
7
7
  }
@@ -3,7 +3,7 @@ import { AbstractPrefetch } from './AbstractPrefetch.js';
3
3
  declare const PrefetchWhenVisible_base: import("@studiometa/js-toolkit").BaseDecorator<import("@studiometa/js-toolkit").WithMountWhenInViewInterface, AbstractPrefetch<import("@studiometa/js-toolkit").BaseProps>, import("@studiometa/js-toolkit").WithMountWhenInViewProps>;
4
4
  /**
5
5
  * PrefetchWhenVisible class.
6
- * @link https://ui.studiometa.dev/-/components/Prefetch/
6
+ * @link https://ui.studiometa.dev/components/Prefetch/
7
7
  */
8
8
  export declare class PrefetchWhenVisible extends PrefetchWhenVisible_base {
9
9
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/Prefetch/PrefetchWhenVisible.ts"],
4
- "sourcesContent": ["import { withMountWhenInView } from '@studiometa/js-toolkit';\nimport type { BaseConfig } from '@studiometa/js-toolkit';\nimport { AbstractPrefetch } from './AbstractPrefetch.js';\n\n/**\n * PrefetchWhenVisible class.\n * @link https://ui.studiometa.dev/-/components/Prefetch/\n */\nexport class PrefetchWhenVisible extends withMountWhenInView<AbstractPrefetch>(AbstractPrefetch) {\n /**\n * Config.\n */\n static config: BaseConfig = {\n ...AbstractPrefetch.config,\n name: 'PrefetchWhenVisible',\n };\n\n /**\n * Prefetch on mount.\n */\n mounted() {\n this.prefetch();\n }\n}\n"],
4
+ "sourcesContent": ["import { withMountWhenInView } from '@studiometa/js-toolkit';\nimport type { BaseConfig } from '@studiometa/js-toolkit';\nimport { AbstractPrefetch } from './AbstractPrefetch.js';\n\n/**\n * PrefetchWhenVisible class.\n * @link https://ui.studiometa.dev/components/Prefetch/\n */\nexport class PrefetchWhenVisible extends withMountWhenInView<AbstractPrefetch>(AbstractPrefetch) {\n /**\n * Config.\n */\n static config: BaseConfig = {\n ...AbstractPrefetch.config,\n name: 'PrefetchWhenVisible',\n };\n\n /**\n * Prefetch on mount.\n */\n mounted() {\n this.prefetch();\n }\n}\n"],
5
5
  "mappings": "AAAA,SAAS,2BAA2B;AAEpC,SAAS,wBAAwB;AAM1B,MAAM,4BAA4B,oBAAsC,gBAAgB,EAAE;AAAA;AAAA;AAAA;AAAA,EAI/F,OAAO,SAAqB;AAAA,IAC1B,GAAG,iBAAiB;AAAA,IACpB,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AACR,SAAK,SAAS;AAAA,EAChB;AACF;",
6
6
  "names": []
7
7
  }
package/README.md CHANGED
@@ -51,6 +51,6 @@ Heads up to [ui.studiometa.dev](https://ui.studiometa.dev) for more informations
51
51
 
52
52
  ## Contributing
53
53
 
54
- Please read the [contribution docs](https://ui.studiometa.dev/-/guide/contributing/).
54
+ Please read the [contribution docs](https://ui.studiometa.dev/guide/contributing/).
55
55
 
56
56
  [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/studiometa/ui)
@@ -8,7 +8,7 @@ export interface ScrollAnimationProps extends BaseProps {
8
8
  declare const ScrollAnimation_base: import("@studiometa/js-toolkit").BaseDecorator<import("@studiometa/js-toolkit").WithScrolledInViewInterface, AbstractScrollAnimation<BaseProps>, import("@studiometa/js-toolkit").WithScrolledInViewProps>;
9
9
  /**
10
10
  * ScrollAnimation class.
11
- * @link https://ui.studiometa.dev/-/components/ScrollAnimation/
11
+ * @link https://ui.studiometa.dev/components/ScrollAnimation/
12
12
  */
13
13
  export declare class ScrollAnimation<T extends BaseProps = BaseProps> extends ScrollAnimation_base<T & ScrollAnimationProps> {
14
14
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/ScrollAnimation/ScrollAnimation.ts"],
4
- "sourcesContent": ["import { withScrolledInView } from '@studiometa/js-toolkit';\nimport type { BaseConfig, BaseProps } from '@studiometa/js-toolkit';\nimport { AbstractScrollAnimation } from './AbstractScrollAnimation.js';\n\nexport interface ScrollAnimationProps extends BaseProps {\n $refs: {\n target: HTMLElement;\n };\n}\n\n/**\n * ScrollAnimation class.\n * @link https://ui.studiometa.dev/-/components/ScrollAnimation/\n */\nexport class ScrollAnimation<\n T extends BaseProps = BaseProps,\n> extends withScrolledInView<AbstractScrollAnimation>(AbstractScrollAnimation, {})<\n T & ScrollAnimationProps\n> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n ...AbstractScrollAnimation.config,\n name: 'ScrollAnimation',\n refs: ['target'],\n };\n\n /**\n * Use the `target` ref as animation target.\n */\n get target(): HTMLElement {\n return this.$refs.target;\n }\n}\n"],
4
+ "sourcesContent": ["import { withScrolledInView } from '@studiometa/js-toolkit';\nimport type { BaseConfig, BaseProps } from '@studiometa/js-toolkit';\nimport { AbstractScrollAnimation } from './AbstractScrollAnimation.js';\n\nexport interface ScrollAnimationProps extends BaseProps {\n $refs: {\n target: HTMLElement;\n };\n}\n\n/**\n * ScrollAnimation class.\n * @link https://ui.studiometa.dev/components/ScrollAnimation/\n */\nexport class ScrollAnimation<\n T extends BaseProps = BaseProps,\n> extends withScrolledInView<AbstractScrollAnimation>(AbstractScrollAnimation, {})<\n T & ScrollAnimationProps\n> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n ...AbstractScrollAnimation.config,\n name: 'ScrollAnimation',\n refs: ['target'],\n };\n\n /**\n * Use the `target` ref as animation target.\n */\n get target(): HTMLElement {\n return this.$refs.target;\n }\n}\n"],
5
5
  "mappings": "AAAA,SAAS,0BAA0B;AAEnC,SAAS,+BAA+B;AAYjC,MAAM,wBAEH,mBAA4C,yBAAyB,CAAC,CAAC,EAE/E;AAAA;AAAA;AAAA;AAAA,EAIA,OAAO,SAAqB;AAAA,IAC1B,GAAG,wBAAwB;AAAA,IAC3B,MAAM;AAAA,IACN,MAAM,CAAC,QAAQ;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAsB;AACxB,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;",
6
6
  "names": []
7
7
  }
@@ -12,7 +12,7 @@ export interface ScrollRevealProps extends BaseProps {
12
12
  declare const ScrollReveal_base: import("@studiometa/js-toolkit").BaseDecorator<import("@studiometa/js-toolkit").WithMountWhenInViewInterface, Transition<BaseProps>, import("@studiometa/js-toolkit").WithMountWhenInViewProps>;
13
13
  /**
14
14
  * ScrollReveal class.
15
- * @link https://ui.studiometa.dev/-/components/ScrollReveal/
15
+ * @link https://ui.studiometa.dev/components/ScrollReveal/
16
16
  */
17
17
  export declare class ScrollReveal<T extends BaseProps = BaseProps> extends ScrollReveal_base<T & ScrollRevealProps> {
18
18
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/ScrollReveal/ScrollReveal.ts"],
4
- "sourcesContent": ["import { withMountWhenInView, useScroll, ScrollServiceProps } from '@studiometa/js-toolkit';\nimport type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';\nimport { Transition } from '../Transition/index.js';\n\nexport interface ScrollRevealProps extends BaseProps {\n $refs: {\n target?: HTMLElement;\n };\n $options: {\n repeat: boolean;\n };\n}\n\n/**\n * ScrollReveal class.\n * @link https://ui.studiometa.dev/-/components/ScrollReveal/\n */\nexport class ScrollReveal<T extends BaseProps = BaseProps> extends withMountWhenInView<Transition>(\n Transition,\n)<T & ScrollRevealProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n ...Transition.config,\n name: 'ScrollReveal',\n refs: ['target'],\n options: {\n ...Transition.config.options,\n enterKeep: {\n type: Boolean,\n default: true,\n },\n repeat: Boolean,\n intersectionObserver: {\n type: Object,\n default: () => ({ threshold: [0, 1] }),\n },\n },\n };\n\n /**\n * Vertical scroll direction.\n */\n static scrollDirectionY: ScrollServiceProps['direction']['y'] = 'NONE';\n\n /**\n * Get the transition target.\n */\n get target(): HTMLElement {\n return this.$refs.target ?? this.$el;\n }\n\n /**\n * Trigger the `enter` transition on mount.\n */\n mounted() {\n if (!this.$options.repeat) {\n this.enter();\n this.$terminate();\n return;\n }\n\n const scroll = useScroll();\n\n if (!scroll.has('ScrollRevealRepeat')) {\n scroll.add('ScrollRevealRepeat', (props) => {\n ScrollReveal.scrollDirectionY = props.direction.y;\n });\n }\n\n if (ScrollReveal.scrollDirectionY !== 'UP') {\n this.enter();\n }\n }\n}\n"],
4
+ "sourcesContent": ["import { withMountWhenInView, useScroll, ScrollServiceProps } from '@studiometa/js-toolkit';\nimport type { BaseProps, BaseConfig } from '@studiometa/js-toolkit';\nimport { Transition } from '../Transition/index.js';\n\nexport interface ScrollRevealProps extends BaseProps {\n $refs: {\n target?: HTMLElement;\n };\n $options: {\n repeat: boolean;\n };\n}\n\n/**\n * ScrollReveal class.\n * @link https://ui.studiometa.dev/components/ScrollReveal/\n */\nexport class ScrollReveal<T extends BaseProps = BaseProps> extends withMountWhenInView<Transition>(\n Transition,\n)<T & ScrollRevealProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n ...Transition.config,\n name: 'ScrollReveal',\n refs: ['target'],\n options: {\n ...Transition.config.options,\n enterKeep: {\n type: Boolean,\n default: true,\n },\n repeat: Boolean,\n intersectionObserver: {\n type: Object,\n default: () => ({ threshold: [0, 1] }),\n },\n },\n };\n\n /**\n * Vertical scroll direction.\n */\n static scrollDirectionY: ScrollServiceProps['direction']['y'] = 'NONE';\n\n /**\n * Get the transition target.\n */\n get target(): HTMLElement {\n return this.$refs.target ?? this.$el;\n }\n\n /**\n * Trigger the `enter` transition on mount.\n */\n mounted() {\n if (!this.$options.repeat) {\n this.enter();\n this.$terminate();\n return;\n }\n\n const scroll = useScroll();\n\n if (!scroll.has('ScrollRevealRepeat')) {\n scroll.add('ScrollRevealRepeat', (props) => {\n ScrollReveal.scrollDirectionY = props.direction.y;\n });\n }\n\n if (ScrollReveal.scrollDirectionY !== 'UP') {\n this.enter();\n }\n }\n}\n"],
5
5
  "mappings": "AAAA,SAAS,qBAAqB,iBAAqC;AAEnE,SAAS,kBAAkB;AAepB,MAAM,qBAAsD;AAAA,EACjE;AACF,EAAyB;AAAA;AAAA;AAAA;AAAA,EAIvB,OAAO,SAAqB;AAAA,IAC1B,GAAG,WAAW;AAAA,IACd,MAAM;AAAA,IACN,MAAM,CAAC,QAAQ;AAAA,IACf,SAAS;AAAA,MACP,GAAG,WAAW,OAAO;AAAA,MACrB,WAAW;AAAA,QACT,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,MACA,QAAQ;AAAA,MACR,sBAAsB;AAAA,QACpB,MAAM;AAAA,QACN,SAAS,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,mBAAyD;AAAA;AAAA;AAAA;AAAA,EAKhE,IAAI,SAAsB;AACxB,WAAO,KAAK,MAAM,UAAU,KAAK;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AACR,QAAI,CAAC,KAAK,SAAS,QAAQ;AACzB,WAAK,MAAM;AACX,WAAK,WAAW;AAChB;AAAA,IACF;AAEA,UAAM,SAAS,UAAU;AAEzB,QAAI,CAAC,OAAO,IAAI,oBAAoB,GAAG;AACrC,aAAO,IAAI,sBAAsB,CAAC,UAAU;AAC1C,qBAAa,mBAAmB,MAAM,UAAU;AAAA,MAClD,CAAC;AAAA,IACH;AAEA,QAAI,aAAa,qBAAqB,MAAM;AAC1C,WAAK,MAAM;AAAA,IACb;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -3,7 +3,7 @@ import type { BaseConfig } from '@studiometa/js-toolkit';
3
3
  declare const Sentinel_base: import("@studiometa/js-toolkit").BaseDecorator<import("@studiometa/js-toolkit").WithIntersectionObserverInterface, Base<import("@studiometa/js-toolkit").BaseProps>, import("@studiometa/js-toolkit").WithIntersectionObserverProps>;
4
4
  /**
5
5
  * Sentinel class.
6
- * @link https://ui.studiometa.dev/-/components/Sentinel/
6
+ * @link https://ui.studiometa.dev/components/Sentinel/
7
7
  */
8
8
  export declare class Sentinel extends Sentinel_base {
9
9
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/Sentinel/Sentinel.ts"],
4
- "sourcesContent": ["import { Base, withIntersectionObserver } from '@studiometa/js-toolkit';\nimport type { BaseConfig } from '@studiometa/js-toolkit';\n\n/**\n * Sentinel class.\n * @link https://ui.studiometa.dev/-/components/Sentinel/\n */\nexport class Sentinel extends withIntersectionObserver(Base, { threshold: [0, 1] }) {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Sentinel',\n };\n}\n"],
4
+ "sourcesContent": ["import { Base, withIntersectionObserver } from '@studiometa/js-toolkit';\nimport type { BaseConfig } from '@studiometa/js-toolkit';\n\n/**\n * Sentinel class.\n * @link https://ui.studiometa.dev/components/Sentinel/\n */\nexport class Sentinel extends withIntersectionObserver(Base, { threshold: [0, 1] }) {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Sentinel',\n };\n}\n"],
5
5
  "mappings": "AAAA,SAAS,MAAM,gCAAgC;AAOxC,MAAM,iBAAiB,yBAAyB,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;AAAA;AAAA;AAAA;AAAA,EAIlF,OAAO,SAAqB;AAAA,IAC1B,MAAM;AAAA,EACR;AACF;",
6
6
  "names": []
7
7
  }
@@ -24,7 +24,7 @@ export interface SliderProps extends BaseProps {
24
24
  }
25
25
  /**
26
26
  * Slider class.
27
- * @link https://ui.studiometa.dev/-/components/Slider/
27
+ * @link https://ui.studiometa.dev/components/Slider/
28
28
  * @todo a11y
29
29
  */
30
30
  export declare class Slider<T extends BaseProps = BaseProps> extends Base<T & SliderProps> {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../packages/ui/Slider/Slider.ts"],
4
- "sourcesContent": ["import { Base } from '@studiometa/js-toolkit';\nimport type {\n BaseProps,\n BaseConfig,\n DragServiceProps,\n KeyServiceProps,\n} from '@studiometa/js-toolkit';\nimport { clamp, inertiaFinalValue, nextFrame } from '@studiometa/js-toolkit/utils';\nimport { SliderDrag } from './SliderDrag.js';\nimport { SliderItem } from './SliderItem.js';\n\nexport type SliderModes = 'left' | 'center' | 'right';\n\ntype SliderState = { x: Record<SliderModes, number> };\n\nexport interface SliderProps extends BaseProps {\n $refs: {\n wrapper: HTMLElement;\n };\n $children: {\n SliderItem: SliderItem[];\n SliderDrag: SliderDrag[];\n };\n $options: {\n mode: SliderModes;\n fitBounds: boolean;\n contain: boolean;\n sensitivity: number;\n dropSensitivity: number;\n };\n}\n\n/**\n * Slider class.\n * @link https://ui.studiometa.dev/-/components/Slider/\n * @todo a11y\n */\nexport class Slider<T extends BaseProps = BaseProps> extends Base<T & SliderProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Slider',\n refs: ['wrapper'],\n emits: ['goto', 'index'],\n components: {\n SliderItem,\n SliderDrag,\n },\n options: {\n mode: { type: String, default: 'left' },\n fitBounds: Boolean,\n contain: Boolean,\n sensitivity: { type: Number, default: 1 },\n dropSensitivity: { type: Number, default: 2 },\n },\n };\n\n /**\n * Distance on the x axis.\n * @private\n */\n __distanceX = 0;\n\n /**\n * Initial x position.\n * @private\n */\n __initialX = 0;\n\n /**\n * Index of the current active slide.\n * @private\n */\n __currentIndex = 0;\n\n /**\n * Store all the states.\n */\n states: SliderState[] = [];\n\n /**\n * Origins for the different modes.\n */\n origins: Record<SliderModes, number> = {\n left: 0,\n center: 0,\n right: 0,\n };\n\n /**\n * Wether or not the wrapper is focused.\n */\n hasFocus = false;\n\n /**\n * Get the current index.\n */\n get currentIndex() {\n return this.__currentIndex;\n }\n\n /**\n * Set the current index and emit the `index` event.\n */\n set currentIndex(value: number) {\n this.currentSliderItem.disactivate();\n this.$emit('index', value);\n this.__currentIndex = value;\n this.currentSliderItem.activate();\n }\n\n /**\n * Get the current state.\n */\n get currentState() {\n return this.states[this.currentIndex];\n }\n\n /**\n * Get the first state.\n */\n get firstState() {\n return this.states[0];\n }\n\n /**\n * Get the last state.\n */\n get lastState() {\n return this.states.at(-1);\n }\n\n /**\n * Get the minimal contain state value.\n */\n get containMinState(): number {\n return this.getStateValueByMode(this.firstState.x, 'left');\n }\n\n /**\n * Get the maximal contain state value.\n */\n get containMaxState(): number {\n return this.getStateValueByMode(this.lastState.x, 'right');\n }\n\n /**\n * Get the last index.\n */\n get indexMax(): number {\n return this.$children.SliderItem.length - 1;\n }\n\n /**\n * Get the current SliderItem\n */\n get currentSliderItem() {\n return this.$children.SliderItem[this.currentIndex];\n }\n\n /**\n * Get the states for each SliderItem.\n */\n getStates(): SliderState[] {\n const { wrapper } = this.$refs;\n const originRect = wrapper.getBoundingClientRect();\n\n this.origins = {\n left: originRect.left,\n center: originRect.x + originRect.width / 2,\n right: originRect.x + originRect.width,\n };\n\n const states: SliderState[] = this.$children.SliderItem.map((item) => ({\n x: {\n left: (item.rect.x - this.origins.left) * -1,\n center: (item.rect.x + item.rect.width / 2 - this.origins.center) * -1,\n right: (item.rect.x + item.rect.width - this.origins.right) * -1,\n },\n }));\n\n if (this.$options.contain) {\n const { mode } = this.$options;\n // Find state where last child has passed the wrapper bound completely\n if (mode === 'left') {\n const lastChild = this.$children.SliderItem.at(-1);\n\n const maxState = states.find((state) => {\n const lastChildPosition =\n lastChild.rect.x - this.origins.left + lastChild.rect.width + state.x.left;\n const diffWithWrapperBound = originRect.width - lastChildPosition;\n if (diffWithWrapperBound > 0) {\n state.x.left = Math.min(state.x.left + diffWithWrapperBound, 0);\n return true;\n }\n\n return false;\n });\n\n if (maxState) {\n return states.map((state) => {\n state.x.left = Math.max(state.x.left, maxState.x.left);\n return state;\n });\n }\n }\n\n if (mode === 'right') {\n const maxStateIndex = states.findIndex((state) => state.x.right <= 0);\n const maxState = maxStateIndex < 0 ? states.at(-1) : states[maxStateIndex - 1];\n\n return states.map((state) => {\n state.x.right = maxStateIndex < 0 ? maxState.x.right : Math.min(state.x.right, 0);\n return state;\n });\n }\n\n if (mode === 'center') {\n this.$warn('The `center` mode is not yet compatible with the `contain` mode.');\n }\n }\n\n return states;\n }\n\n /**\n * Get an origin by mode.\n */\n getOriginByMode(mode?: SliderModes) {\n return this.origins[mode ?? this.$options.mode];\n }\n\n /**\n * Get a state value according to the given mode.\n */\n getStateValueByMode(state: SliderState['x'], mode?: SliderModes) {\n return state[mode ?? this.$options.mode];\n }\n\n /**\n * Mounted hook.\n */\n mounted() {\n this.states = this.getStates();\n this.setAccessibilityAttributes();\n this.goTo(this.currentIndex);\n }\n\n /**\n * Resized hook.\n */\n resized() {\n nextFrame(() => {\n this.states = this.getStates();\n nextFrame(() => {\n this.goTo(this.currentIndex);\n });\n });\n }\n\n /**\n * Set accessibility attributes for the component\n */\n setAccessibilityAttributes() {\n this.$el.setAttribute('role', 'group');\n this.$el.setAttribute('aria-roledescription', 'carousel');\n }\n\n /**\n * Go to the next slide.\n */\n goNext() {\n if (this.currentIndex + 1 > this.indexMax) {\n return;\n }\n\n this.goTo(this.currentIndex + 1);\n }\n\n /**\n * Go to the previous slide.\n */\n goPrev() {\n if (this.currentIndex - 1 < 0) {\n return;\n }\n\n this.goTo(this.currentIndex - 1);\n }\n\n /**\n * Go to the given index.\n */\n goTo(index: number) {\n if (index < 0 || index > this.indexMax) {\n throw new Error('Index out of bound.');\n }\n\n const state = this.getStateValueByMode(this.states[index].x);\n\n for (const item of this.$children.SliderItem) {\n item.move(state);\n }\n\n this.currentIndex = index;\n this.$emit('goto', index);\n }\n\n /**\n * Listen to the Draggable `start` event.\n */\n onSliderDragStart() {\n this.__initialX = this.currentSliderItem ? this.currentSliderItem.x : 0;\n this.__distanceX = this.__initialX;\n }\n\n /**\n * Listen to the Draggable `drag` event.\n */\n onSliderDragDrag({ args: [props] }: { args: [DragServiceProps] }) {\n this.__distanceX = this.__initialX + props.distance.x * this.$options.sensitivity;\n\n for (const item of this.$children.SliderItem) {\n item.moveInstantly(this.__distanceX);\n }\n }\n\n /**\n * Listen to the Draggable `drop` event and find the new active slide.\n */\n onSliderDragDrop({ args: [props] }: { args: [DragServiceProps] }) {\n let finalX = clamp(\n inertiaFinalValue(this.__distanceX, props.delta.x * this.$options.dropSensitivity),\n this.getStateValueByMode(this.firstState.x),\n this.getStateValueByMode(this.lastState.x),\n );\n\n const absoluteDifferencesBetweenDistanceAndState = this.states.map((state) =>\n Math.abs(finalX - this.getStateValueByMode(state.x)),\n );\n const minimumDifference = Math.min(...absoluteDifferencesBetweenDistanceAndState);\n const closestIndex = absoluteDifferencesBetweenDistanceAndState.indexOf(minimumDifference);\n\n if (this.$options.fitBounds) {\n this.goTo(closestIndex);\n } else {\n if (this.$options.contain) {\n finalX = Math.min(this.containMinState, finalX);\n finalX = Math.max(this.containMaxState, finalX);\n }\n for (const item of this.$children.SliderItem) {\n item.move(finalX);\n }\n this.currentIndex = closestIndex;\n }\n }\n\n /**\n * Enable focus.\n */\n onWrapperFocus() {\n this.hasFocus = true;\n }\n\n /**\n * Disable focus.\n */\n onWrapperBlur() {\n this.hasFocus = false;\n }\n\n /**\n * Go prev or next when focus is on the wrapper and pressing arrow keys.\n */\n keyed({ LEFT, RIGHT, isDown }: KeyServiceProps) {\n if (this.hasFocus && isDown) {\n if (LEFT) {\n this.goPrev();\n } else if (RIGHT) {\n this.goNext();\n }\n }\n }\n}\n"],
4
+ "sourcesContent": ["import { Base } from '@studiometa/js-toolkit';\nimport type {\n BaseProps,\n BaseConfig,\n DragServiceProps,\n KeyServiceProps,\n} from '@studiometa/js-toolkit';\nimport { clamp, inertiaFinalValue, nextFrame } from '@studiometa/js-toolkit/utils';\nimport { SliderDrag } from './SliderDrag.js';\nimport { SliderItem } from './SliderItem.js';\n\nexport type SliderModes = 'left' | 'center' | 'right';\n\ntype SliderState = { x: Record<SliderModes, number> };\n\nexport interface SliderProps extends BaseProps {\n $refs: {\n wrapper: HTMLElement;\n };\n $children: {\n SliderItem: SliderItem[];\n SliderDrag: SliderDrag[];\n };\n $options: {\n mode: SliderModes;\n fitBounds: boolean;\n contain: boolean;\n sensitivity: number;\n dropSensitivity: number;\n };\n}\n\n/**\n * Slider class.\n * @link https://ui.studiometa.dev/components/Slider/\n * @todo a11y\n */\nexport class Slider<T extends BaseProps = BaseProps> extends Base<T & SliderProps> {\n /**\n * Config.\n */\n static config: BaseConfig = {\n name: 'Slider',\n refs: ['wrapper'],\n emits: ['goto', 'index'],\n components: {\n SliderItem,\n SliderDrag,\n },\n options: {\n mode: { type: String, default: 'left' },\n fitBounds: Boolean,\n contain: Boolean,\n sensitivity: { type: Number, default: 1 },\n dropSensitivity: { type: Number, default: 2 },\n },\n };\n\n /**\n * Distance on the x axis.\n * @private\n */\n __distanceX = 0;\n\n /**\n * Initial x position.\n * @private\n */\n __initialX = 0;\n\n /**\n * Index of the current active slide.\n * @private\n */\n __currentIndex = 0;\n\n /**\n * Store all the states.\n */\n states: SliderState[] = [];\n\n /**\n * Origins for the different modes.\n */\n origins: Record<SliderModes, number> = {\n left: 0,\n center: 0,\n right: 0,\n };\n\n /**\n * Wether or not the wrapper is focused.\n */\n hasFocus = false;\n\n /**\n * Get the current index.\n */\n get currentIndex() {\n return this.__currentIndex;\n }\n\n /**\n * Set the current index and emit the `index` event.\n */\n set currentIndex(value: number) {\n this.currentSliderItem.disactivate();\n this.$emit('index', value);\n this.__currentIndex = value;\n this.currentSliderItem.activate();\n }\n\n /**\n * Get the current state.\n */\n get currentState() {\n return this.states[this.currentIndex];\n }\n\n /**\n * Get the first state.\n */\n get firstState() {\n return this.states[0];\n }\n\n /**\n * Get the last state.\n */\n get lastState() {\n return this.states.at(-1);\n }\n\n /**\n * Get the minimal contain state value.\n */\n get containMinState(): number {\n return this.getStateValueByMode(this.firstState.x, 'left');\n }\n\n /**\n * Get the maximal contain state value.\n */\n get containMaxState(): number {\n return this.getStateValueByMode(this.lastState.x, 'right');\n }\n\n /**\n * Get the last index.\n */\n get indexMax(): number {\n return this.$children.SliderItem.length - 1;\n }\n\n /**\n * Get the current SliderItem\n */\n get currentSliderItem() {\n return this.$children.SliderItem[this.currentIndex];\n }\n\n /**\n * Get the states for each SliderItem.\n */\n getStates(): SliderState[] {\n const { wrapper } = this.$refs;\n const originRect = wrapper.getBoundingClientRect();\n\n this.origins = {\n left: originRect.left,\n center: originRect.x + originRect.width / 2,\n right: originRect.x + originRect.width,\n };\n\n const states: SliderState[] = this.$children.SliderItem.map((item) => ({\n x: {\n left: (item.rect.x - this.origins.left) * -1,\n center: (item.rect.x + item.rect.width / 2 - this.origins.center) * -1,\n right: (item.rect.x + item.rect.width - this.origins.right) * -1,\n },\n }));\n\n if (this.$options.contain) {\n const { mode } = this.$options;\n // Find state where last child has passed the wrapper bound completely\n if (mode === 'left') {\n const lastChild = this.$children.SliderItem.at(-1);\n\n const maxState = states.find((state) => {\n const lastChildPosition =\n lastChild.rect.x - this.origins.left + lastChild.rect.width + state.x.left;\n const diffWithWrapperBound = originRect.width - lastChildPosition;\n if (diffWithWrapperBound > 0) {\n state.x.left = Math.min(state.x.left + diffWithWrapperBound, 0);\n return true;\n }\n\n return false;\n });\n\n if (maxState) {\n return states.map((state) => {\n state.x.left = Math.max(state.x.left, maxState.x.left);\n return state;\n });\n }\n }\n\n if (mode === 'right') {\n const maxStateIndex = states.findIndex((state) => state.x.right <= 0);\n const maxState = maxStateIndex < 0 ? states.at(-1) : states[maxStateIndex - 1];\n\n return states.map((state) => {\n state.x.right = maxStateIndex < 0 ? maxState.x.right : Math.min(state.x.right, 0);\n return state;\n });\n }\n\n if (mode === 'center') {\n this.$warn('The `center` mode is not yet compatible with the `contain` mode.');\n }\n }\n\n return states;\n }\n\n /**\n * Get an origin by mode.\n */\n getOriginByMode(mode?: SliderModes) {\n return this.origins[mode ?? this.$options.mode];\n }\n\n /**\n * Get a state value according to the given mode.\n */\n getStateValueByMode(state: SliderState['x'], mode?: SliderModes) {\n return state[mode ?? this.$options.mode];\n }\n\n /**\n * Mounted hook.\n */\n mounted() {\n this.states = this.getStates();\n this.setAccessibilityAttributes();\n this.goTo(this.currentIndex);\n }\n\n /**\n * Resized hook.\n */\n resized() {\n nextFrame(() => {\n this.states = this.getStates();\n nextFrame(() => {\n this.goTo(this.currentIndex);\n });\n });\n }\n\n /**\n * Set accessibility attributes for the component\n */\n setAccessibilityAttributes() {\n this.$el.setAttribute('role', 'group');\n this.$el.setAttribute('aria-roledescription', 'carousel');\n }\n\n /**\n * Go to the next slide.\n */\n goNext() {\n if (this.currentIndex + 1 > this.indexMax) {\n return;\n }\n\n this.goTo(this.currentIndex + 1);\n }\n\n /**\n * Go to the previous slide.\n */\n goPrev() {\n if (this.currentIndex - 1 < 0) {\n return;\n }\n\n this.goTo(this.currentIndex - 1);\n }\n\n /**\n * Go to the given index.\n */\n goTo(index: number) {\n if (index < 0 || index > this.indexMax) {\n throw new Error('Index out of bound.');\n }\n\n const state = this.getStateValueByMode(this.states[index].x);\n\n for (const item of this.$children.SliderItem) {\n item.move(state);\n }\n\n this.currentIndex = index;\n this.$emit('goto', index);\n }\n\n /**\n * Listen to the Draggable `start` event.\n */\n onSliderDragStart() {\n this.__initialX = this.currentSliderItem ? this.currentSliderItem.x : 0;\n this.__distanceX = this.__initialX;\n }\n\n /**\n * Listen to the Draggable `drag` event.\n */\n onSliderDragDrag({ args: [props] }: { args: [DragServiceProps] }) {\n this.__distanceX = this.__initialX + props.distance.x * this.$options.sensitivity;\n\n for (const item of this.$children.SliderItem) {\n item.moveInstantly(this.__distanceX);\n }\n }\n\n /**\n * Listen to the Draggable `drop` event and find the new active slide.\n */\n onSliderDragDrop({ args: [props] }: { args: [DragServiceProps] }) {\n let finalX = clamp(\n inertiaFinalValue(this.__distanceX, props.delta.x * this.$options.dropSensitivity),\n this.getStateValueByMode(this.firstState.x),\n this.getStateValueByMode(this.lastState.x),\n );\n\n const absoluteDifferencesBetweenDistanceAndState = this.states.map((state) =>\n Math.abs(finalX - this.getStateValueByMode(state.x)),\n );\n const minimumDifference = Math.min(...absoluteDifferencesBetweenDistanceAndState);\n const closestIndex = absoluteDifferencesBetweenDistanceAndState.indexOf(minimumDifference);\n\n if (this.$options.fitBounds) {\n this.goTo(closestIndex);\n } else {\n if (this.$options.contain) {\n finalX = Math.min(this.containMinState, finalX);\n finalX = Math.max(this.containMaxState, finalX);\n }\n for (const item of this.$children.SliderItem) {\n item.move(finalX);\n }\n this.currentIndex = closestIndex;\n }\n }\n\n /**\n * Enable focus.\n */\n onWrapperFocus() {\n this.hasFocus = true;\n }\n\n /**\n * Disable focus.\n */\n onWrapperBlur() {\n this.hasFocus = false;\n }\n\n /**\n * Go prev or next when focus is on the wrapper and pressing arrow keys.\n */\n keyed({ LEFT, RIGHT, isDown }: KeyServiceProps) {\n if (this.hasFocus && isDown) {\n if (LEFT) {\n this.goPrev();\n } else if (RIGHT) {\n this.goNext();\n }\n }\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }