ember-primitives 0.62.0 → 0.63.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 (89) hide show
  1. package/README.md +1 -1
  2. package/declarations/components/accordion/content.d.ts +2 -1
  3. package/declarations/components/accordion/content.d.ts.map +1 -1
  4. package/declarations/components/accordion/header.d.ts +2 -1
  5. package/declarations/components/accordion/header.d.ts.map +1 -1
  6. package/declarations/components/accordion/item.d.ts +7 -0
  7. package/declarations/components/accordion/item.d.ts.map +1 -1
  8. package/declarations/components/accordion/public.d.ts +3 -3
  9. package/declarations/components/accordion/public.d.ts.map +1 -1
  10. package/declarations/components/accordion/trigger.d.ts +2 -1
  11. package/declarations/components/accordion/trigger.d.ts.map +1 -1
  12. package/declarations/components/command-palette.d.ts +13 -0
  13. package/declarations/components/command-palette.d.ts.map +1 -1
  14. package/declarations/components/dialog.d.ts +14 -6
  15. package/declarations/components/dialog.d.ts.map +1 -1
  16. package/declarations/components/drawer.d.ts +14 -6
  17. package/declarations/components/drawer.d.ts.map +1 -1
  18. package/declarations/components/link.d.ts.map +1 -1
  19. package/declarations/components/menu.d.ts.map +1 -1
  20. package/declarations/components/one-time-password/otp.d.ts +1 -1
  21. package/declarations/components/one-time-password/utils.d.ts.map +1 -1
  22. package/declarations/components/rating/range.d.ts +1 -0
  23. package/declarations/components/rating/range.d.ts.map +1 -1
  24. package/declarations/components/rating/rating.d.ts +1 -1
  25. package/declarations/components/rating/rating.d.ts.map +1 -1
  26. package/declarations/components/rating/stars.d.ts.map +1 -1
  27. package/declarations/components/rating/state.d.ts +1 -0
  28. package/declarations/components/rating/state.d.ts.map +1 -1
  29. package/declarations/components/slider.d.ts +2 -0
  30. package/declarations/components/slider.d.ts.map +1 -1
  31. package/declarations/components/switch.d.ts +5 -1
  32. package/declarations/components/switch.d.ts.map +1 -1
  33. package/declarations/components/tabs.d.ts +30 -1
  34. package/declarations/components/tabs.d.ts.map +1 -1
  35. package/declarations/components/zoetrope/index.d.ts.map +1 -1
  36. package/dist/components/accordion.js +12 -4
  37. package/dist/components/accordion.js.map +1 -1
  38. package/dist/components/command-palette.js +8 -1
  39. package/dist/components/command-palette.js.map +1 -1
  40. package/dist/components/dialog.js +9 -2
  41. package/dist/components/dialog.js.map +1 -1
  42. package/dist/components/drawer.js +9 -2
  43. package/dist/components/drawer.js.map +1 -1
  44. package/dist/components/link.js +1 -1
  45. package/dist/components/link.js.map +1 -1
  46. package/dist/components/menu.js +5 -1
  47. package/dist/components/menu.js.map +1 -1
  48. package/dist/components/one-time-password.js +1 -1
  49. package/dist/components/rating.js +1 -1
  50. package/dist/components/slider.js +6 -1
  51. package/dist/components/switch.js +1 -1
  52. package/dist/components/switch.js.map +1 -1
  53. package/dist/components/tabs.js +18 -5
  54. package/dist/components/tabs.js.map +1 -1
  55. package/dist/components/zoetrope/styles.css +6 -1
  56. package/dist/components/zoetrope.js +1 -1
  57. package/dist/{index-gRO4Cvlf.js → index-B-yrfUe9.js} +10 -3
  58. package/dist/index-B-yrfUe9.js.map +1 -0
  59. package/dist/index.js +3 -3
  60. package/dist/{otp-H5a4B4yu.js → otp-C8c1EIw6.js} +27 -15
  61. package/dist/otp-C8c1EIw6.js.map +1 -0
  62. package/dist/{rating-BrIiwDLw.js → rating-CKWhrr-L.js} +9 -5
  63. package/dist/rating-CKWhrr-L.js.map +1 -0
  64. package/package.json +1 -1
  65. package/src/components/accordion/content.gts +4 -2
  66. package/src/components/accordion/header.gts +8 -2
  67. package/src/components/accordion/item.gts +18 -2
  68. package/src/components/accordion/public.ts +12 -3
  69. package/src/components/accordion/trigger.gts +5 -3
  70. package/src/components/command-palette.gts +22 -0
  71. package/src/components/dialog.gts +15 -3
  72. package/src/components/drawer.gts +15 -3
  73. package/src/components/link.gts +1 -0
  74. package/src/components/menu.gts +7 -0
  75. package/src/components/one-time-password/input.gts +1 -1
  76. package/src/components/one-time-password/otp.gts +1 -1
  77. package/src/components/one-time-password/utils.ts +26 -13
  78. package/src/components/rating/range.gts +3 -0
  79. package/src/components/rating/rating.gts +7 -2
  80. package/src/components/rating/stars.gts +0 -1
  81. package/src/components/rating/state.gts +9 -0
  82. package/src/components/slider.gts +8 -0
  83. package/src/components/switch.gts +5 -2
  84. package/src/components/tabs.gts +35 -4
  85. package/src/components/zoetrope/index.gts +12 -3
  86. package/src/components/zoetrope/styles.css +6 -1
  87. package/dist/index-gRO4Cvlf.js.map +0 -1
  88. package/dist/otp-H5a4B4yu.js.map +0 -1
  89. package/dist/rating-BrIiwDLw.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"menu.js","sources":["../../src/components/menu.gts"],"sourcesContent":["import Component from \"@glimmer/component\";\nimport { hash } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\nimport { guidFor } from \"@ember/object/internals\";\n\nimport { modifier as eModifier } from \"ember-modifier\";\nimport { cell } from \"ember-resources\";\nimport { getTabster, getTabsterAttribute, MoverDirections, setTabsterAttribute } from \"tabster\";\n\nimport { Link, type Signature as LinkSignature } from \"./link.gts\";\nimport { Popover, type Signature as PopoverSignature } from \"./popover.gts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type { WithBoundArgs } from \"@glint/template\";\n\ntype Cell<V> = ReturnType<typeof cell<V>>;\ntype LinkArgs = LinkSignature[\"Args\"];\ntype PopoverArgs = PopoverSignature[\"Args\"];\ntype PopoverBlockParams = PopoverSignature[\"Blocks\"][\"default\"][0];\n\nconst TABSTER_CONFIG_CONTENT = getTabsterAttribute(\n {\n mover: {\n direction: MoverDirections.Both,\n cyclic: true,\n },\n deloser: {},\n },\n true,\n);\n\nconst TABSTER_CONFIG_TRIGGER = {\n deloser: {},\n};\n\nexport interface Signature {\n Args: PopoverArgs;\n Blocks: {\n default: [\n {\n arrow: PopoverBlockParams[\"arrow\"];\n trigger: WithBoundArgs<\n typeof trigger,\n \"triggerElement\" | \"contentId\" | \"isOpen\" | \"setReference\"\n >;\n Trigger: WithBoundArgs<typeof Trigger, \"triggerModifier\">;\n Content: WithBoundArgs<\n typeof Content,\n \"triggerElement\" | \"contentId\" | \"isOpen\" | \"PopoverContent\"\n >;\n isOpen: boolean;\n },\n ];\n };\n}\n\nexport interface SeparatorSignature {\n Element: HTMLDivElement;\n Blocks: { default: [] };\n}\n\nconst Separator: TOC<SeparatorSignature> = <template>\n <div role=\"separator\" ...attributes>\n {{yield}}\n </div>\n</template>;\n\n/**\n * We focus items on `pointerMove` to achieve the following:\n *\n * - Mouse over an item (it focuses)\n * - Leave mouse where it is and use keyboard to focus a different item\n * - Wiggle mouse without it leaving previously focused item\n * - Previously focused item should re-focus\n *\n * If we used `mouseOver`/`mouseEnter` it would not re-focus when the mouse\n * wiggles. This is to match native menu implementation.\n */\nfunction focusOnHover(e: PointerEvent) {\n const item = e.currentTarget;\n\n if (item instanceof HTMLElement) {\n item?.focus();\n }\n}\n\ninterface PrivateItemSignature {\n Element: HTMLButtonElement;\n Args: { onSelect?: (event: Event) => void; toggle: () => void };\n Blocks: { default: [] };\n}\n\nexport interface ItemSignature {\n Element: PrivateItemSignature[\"Element\"];\n Args: Omit<PrivateItemSignature[\"Args\"], \"toggle\">;\n Blocks: PrivateItemSignature[\"Blocks\"];\n}\n\nconst Item: TOC<PrivateItemSignature> = <template>\n {{! @glint-expect-error }}\n {{#let (if @onSelect (modifier on \"click\" @onSelect)) as |maybeClick|}}\n <button\n type=\"button\"\n role=\"menuitem\"\n {{! @glint-expect-error }}\n {{maybeClick}}\n {{on \"click\" @toggle}}\n {{on \"pointermove\" focusOnHover}}\n ...attributes\n >\n {{yield}}\n </button>\n {{/let}}\n</template>;\n\ninterface LinkItemArgs extends LinkArgs {\n toggle: () => void;\n}\n\ninterface PrivateLinkItemSignature {\n Element: HTMLAnchorElement;\n Args: LinkItemArgs;\n Blocks: { default: [] };\n}\n\nexport interface LinkItemSignature {\n Element: PrivateLinkItemSignature[\"Element\"];\n Args: LinkArgs;\n Blocks: PrivateLinkItemSignature[\"Blocks\"];\n}\n\nconst LinkItem: TOC<PrivateLinkItemSignature> = <template>\n <Link\n role=\"menuitem\"\n @href={{@href}}\n @includeActiveQueryParams={{@includeActiveQueryParams}}\n @activeOnSubPaths={{@activeOnSubPaths}}\n {{on \"click\" @toggle}}\n {{on \"pointermove\" focusOnHover}}\n ...attributes\n >\n {{yield}}\n </Link>\n</template>;\n\nconst installContent = eModifier<{\n Element: HTMLElement;\n Args: {\n Named: {\n isOpen: Cell<boolean>;\n triggerElement: Cell<HTMLElement>;\n };\n };\n}>((element, _: [], { isOpen, triggerElement }) => {\n // Focus first focusable element when the popover opens.\n // The toggle event fires natively after showPopover() completes.\n // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/toggle_event\n function onToggle(e: ToggleEvent) {\n if (e.newState !== \"open\") return;\n\n const tabster = getTabster(window);\n const firstFocusable = tabster?.focusable.findFirst({\n container: element,\n });\n\n firstFocusable?.focus();\n }\n\n element.addEventListener(\"toggle\", onToggle as EventListener);\n\n // listen for \"outside\" clicks\n function onDocumentClick(e: MouseEvent) {\n if (\n isOpen.current &&\n e.target &&\n !element.contains(e.target as HTMLElement) &&\n !triggerElement.current?.contains(e.target as HTMLElement)\n ) {\n isOpen.current = false;\n }\n }\n\n // listen for the escape key\n function onDocumentKeydown(e: KeyboardEvent) {\n if (isOpen.current && e.key === \"Escape\") {\n isOpen.current = false;\n }\n }\n\n document.addEventListener(\"click\", onDocumentClick);\n document.addEventListener(\"keydown\", onDocumentKeydown);\n\n return () => {\n element.removeEventListener(\"toggle\", onToggle as EventListener);\n document.removeEventListener(\"click\", onDocumentClick);\n document.removeEventListener(\"keydown\", onDocumentKeydown);\n };\n});\n\ninterface PrivateContentSignature {\n Element: HTMLDivElement;\n Args: {\n triggerElement: Cell<HTMLElement>;\n contentId: string;\n isOpen: Cell<boolean>;\n PopoverContent: PopoverBlockParams[\"Content\"];\n };\n Blocks: {\n default: [\n {\n Item: WithBoundArgs<typeof Item, \"toggle\">;\n LinkItem: WithBoundArgs<typeof LinkItem, \"toggle\">;\n Separator: typeof Separator;\n },\n ];\n };\n}\n\nexport interface ContentSignature {\n Element: PrivateContentSignature[\"Element\"];\n Blocks: PrivateContentSignature[\"Blocks\"];\n}\n\nconst Content: TOC<PrivateContentSignature> = <template>\n {{#if @isOpen.current}}\n <@PopoverContent\n id={{@contentId}}\n role=\"menu\"\n data-tabster={{TABSTER_CONFIG_CONTENT}}\n tabindex=\"0\"\n {{installContent isOpen=@isOpen triggerElement=@triggerElement}}\n ...attributes\n >\n {{yield\n (hash\n Item=(component Item toggle=@isOpen.toggle)\n LinkItem=(component LinkItem toggle=@isOpen.toggle)\n Separator=Separator\n )\n }}\n </@PopoverContent>\n {{/if}}\n</template>;\n\ninterface PrivateTriggerModifierSignature {\n Element: HTMLElement;\n Args: {\n Named: {\n triggerElement: Cell<HTMLElement>;\n isOpen: Cell<boolean>;\n contentId: string;\n setReference: PopoverBlockParams[\"setReference\"];\n stopPropagation?: boolean;\n preventDefault?: boolean;\n };\n };\n}\n\nexport interface TriggerModifierSignature {\n Element: PrivateTriggerModifierSignature[\"Element\"];\n}\n\nconst trigger = eModifier<PrivateTriggerModifierSignature>(\n (\n element,\n _: [],\n { triggerElement, isOpen, contentId, setReference, stopPropagation, preventDefault },\n ) => {\n element.setAttribute(\"aria-haspopup\", \"menu\");\n\n if (isOpen.current) {\n element.setAttribute(\"aria-controls\", contentId);\n element.setAttribute(\"aria-expanded\", \"true\");\n } else {\n element.removeAttribute(\"aria-controls\");\n element.setAttribute(\"aria-expanded\", \"false\");\n }\n\n setTabsterAttribute(element, TABSTER_CONFIG_TRIGGER);\n\n const onTriggerClick = (event: MouseEvent) => {\n if (stopPropagation) {\n event.stopPropagation();\n }\n\n if (preventDefault) {\n event.preventDefault();\n }\n\n isOpen.toggle();\n };\n\n element.addEventListener(\"click\", onTriggerClick);\n\n triggerElement.current = element;\n\n setReference(element);\n\n return () => {\n element.removeEventListener(\"click\", onTriggerClick);\n };\n },\n);\n\ninterface PrivateTriggerSignature {\n Element: HTMLButtonElement;\n Args: {\n triggerModifier: WithBoundArgs<\n typeof trigger,\n \"triggerElement\" | \"contentId\" | \"isOpen\" | \"setReference\"\n >;\n stopPropagation?: boolean;\n preventDefault?: boolean;\n };\n Blocks: { default: [] };\n}\n\nexport interface TriggerSignature {\n Element: PrivateTriggerSignature[\"Element\"];\n Blocks: PrivateTriggerSignature[\"Blocks\"];\n}\n\nconst Trigger: TOC<PrivateTriggerSignature> = <template>\n <button\n type=\"button\"\n {{@triggerModifier stopPropagation=@stopPropagation preventDefault=@preventDefault}}\n ...attributes\n >\n {{yield}}\n </button>\n</template>;\n\nconst IsOpen = () => cell<boolean>(false);\nconst TriggerElement = () => cell<HTMLElement>();\n\nexport class Menu extends Component<Signature> {\n contentId = guidFor(this);\n\n <template>\n {{#let (IsOpen) (TriggerElement) as |isOpen triggerEl|}}\n <Popover\n @flipOptions={{@flipOptions}}\n @middleware={{@middleware}}\n @offsetOptions={{@offsetOptions}}\n @placement={{@placement}}\n @shiftOptions={{@shiftOptions}}\n @strategy={{@strategy}}\n as |p|\n >\n {{#let\n (modifier\n trigger\n triggerElement=triggerEl\n isOpen=isOpen\n contentId=this.contentId\n setReference=p.setReference\n )\n as |triggerModifier|\n }}\n {{yield\n (hash\n trigger=triggerModifier\n Trigger=(component Trigger triggerModifier=triggerModifier)\n Content=(component\n Content\n PopoverContent=p.Content\n isOpen=isOpen\n triggerElement=triggerEl\n contentId=this.contentId\n )\n arrow=p.arrow\n isOpen=isOpen.current\n )\n }}\n {{/let}}\n </Popover>\n {{/let}}\n </template>\n}\n\nexport default Menu;\n"],"names":["TABSTER_CONFIG_CONTENT","getTabsterAttribute","mover","direction","MoverDirections","Both","cyclic","deloser","TABSTER_CONFIG_TRIGGER","Separator","setComponentTemplate","precompileTemplate","strictMode","templateOnly","focusOnHover","e","item","currentTarget","HTMLElement","focus","Item","scope","on","LinkItem","Link","installContent","eModifier","element","_","isOpen","triggerElement","onToggle","newState","tabster","getTabster","window","firstFocusable","focusable","findFirst","container","addEventListener","onDocumentClick","current","target","contains","onDocumentKeydown","key","document","removeEventListener","Content","hash","trigger","contentId","setReference","stopPropagation","preventDefault","setAttribute","removeAttribute","setTabsterAttribute","onTriggerClick","event","toggle","Trigger","IsOpen","cell","TriggerElement","Menu","Component","guidFor","Popover"],"mappings":"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"}
1
+ {"version":3,"file":"menu.js","sources":["../../src/components/menu.gts"],"sourcesContent":["import Component from \"@glimmer/component\";\nimport { hash } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\nimport { guidFor } from \"@ember/object/internals\";\n\nimport { modifier as eModifier } from \"ember-modifier\";\nimport { cell } from \"ember-resources\";\nimport { getTabster, getTabsterAttribute, MoverDirections, setTabsterAttribute } from \"tabster\";\n\nimport { Link, type Signature as LinkSignature } from \"./link.gts\";\nimport { Popover, type Signature as PopoverSignature } from \"./popover.gts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type { WithBoundArgs } from \"@glint/template\";\n\ntype Cell<V> = ReturnType<typeof cell<V>>;\ntype LinkArgs = LinkSignature[\"Args\"];\ntype PopoverArgs = PopoverSignature[\"Args\"];\ntype PopoverBlockParams = PopoverSignature[\"Blocks\"][\"default\"][0];\n\nconst TABSTER_CONFIG_CONTENT = getTabsterAttribute(\n {\n mover: {\n direction: MoverDirections.Both,\n cyclic: true,\n },\n deloser: {},\n },\n true,\n);\n\nconst TABSTER_CONFIG_TRIGGER = {\n deloser: {},\n};\n\nexport interface Signature {\n Args: PopoverArgs;\n Blocks: {\n default: [\n {\n arrow: PopoverBlockParams[\"arrow\"];\n trigger: WithBoundArgs<\n typeof trigger,\n \"triggerElement\" | \"contentId\" | \"isOpen\" | \"setReference\"\n >;\n Trigger: WithBoundArgs<typeof Trigger, \"triggerModifier\">;\n Content: WithBoundArgs<\n typeof Content,\n \"triggerElement\" | \"contentId\" | \"isOpen\" | \"PopoverContent\"\n >;\n isOpen: boolean;\n },\n ];\n };\n}\n\nexport interface SeparatorSignature {\n Element: HTMLDivElement;\n Blocks: { default: [] };\n}\n\nconst Separator: TOC<SeparatorSignature> = <template>\n <div role=\"separator\" ...attributes>\n {{yield}}\n </div>\n</template>;\n\n/**\n * We focus items on `pointerMove` to achieve the following:\n *\n * - Mouse over an item (it focuses)\n * - Leave mouse where it is and use keyboard to focus a different item\n * - Wiggle mouse without it leaving previously focused item\n * - Previously focused item should re-focus\n *\n * If we used `mouseOver`/`mouseEnter` it would not re-focus when the mouse\n * wiggles. This is to match native menu implementation.\n */\nfunction focusOnHover(e: PointerEvent) {\n const item = e.currentTarget;\n\n if (item instanceof HTMLElement) {\n item?.focus();\n }\n}\n\ninterface PrivateItemSignature {\n Element: HTMLButtonElement;\n Args: { onSelect?: (event: Event) => void; toggle: () => void };\n Blocks: { default: [] };\n}\n\nexport interface ItemSignature {\n Element: PrivateItemSignature[\"Element\"];\n Args: Omit<PrivateItemSignature[\"Args\"], \"toggle\">;\n Blocks: PrivateItemSignature[\"Blocks\"];\n}\n\nconst Item: TOC<PrivateItemSignature> = <template>\n {{! @glint-expect-error }}\n {{#let (if @onSelect (modifier on \"click\" @onSelect)) as |maybeClick|}}\n <button\n type=\"button\"\n role=\"menuitem\"\n {{! @glint-expect-error }}\n {{maybeClick}}\n {{on \"click\" @toggle}}\n {{on \"pointermove\" focusOnHover}}\n ...attributes\n >\n {{yield}}\n </button>\n {{/let}}\n</template>;\n\ninterface LinkItemArgs extends LinkArgs {\n toggle: () => void;\n}\n\ninterface PrivateLinkItemSignature {\n Element: HTMLAnchorElement;\n Args: LinkItemArgs;\n Blocks: { default: [] };\n}\n\nexport interface LinkItemSignature {\n Element: PrivateLinkItemSignature[\"Element\"];\n Args: LinkArgs;\n Blocks: PrivateLinkItemSignature[\"Blocks\"];\n}\n\nconst LinkItem: TOC<PrivateLinkItemSignature> = <template>\n <Link\n role=\"menuitem\"\n @href={{@href}}\n @includeActiveQueryParams={{@includeActiveQueryParams}}\n @activeOnSubPaths={{@activeOnSubPaths}}\n {{on \"click\" @toggle}}\n {{on \"pointermove\" focusOnHover}}\n ...attributes\n >\n {{yield}}\n </Link>\n</template>;\n\nconst installContent = eModifier<{\n Element: HTMLElement;\n Args: {\n Named: {\n isOpen: Cell<boolean>;\n triggerElement: Cell<HTMLElement>;\n };\n };\n}>((element, _: [], { isOpen, triggerElement }) => {\n // Focus first focusable element when the popover opens.\n // The toggle event fires natively after showPopover() completes.\n // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/toggle_event\n function onToggle(e: ToggleEvent) {\n if (e.newState !== \"open\") return;\n\n const tabster = getTabster(window);\n const firstFocusable = tabster?.focusable.findFirst({\n container: element,\n });\n\n firstFocusable?.focus();\n }\n\n element.addEventListener(\"toggle\", onToggle as EventListener);\n\n // listen for \"outside\" clicks\n function onDocumentClick(e: MouseEvent) {\n if (\n isOpen.current &&\n e.target &&\n !element.contains(e.target as HTMLElement) &&\n !triggerElement.current?.contains(e.target as HTMLElement)\n ) {\n isOpen.current = false;\n }\n }\n\n // listen for the escape key\n function onDocumentKeydown(e: KeyboardEvent) {\n if (isOpen.current && e.key === \"Escape\") {\n /** Otherwise the same key press also closes a `<dialog>` around the menu. */\n e.preventDefault();\n isOpen.current = false;\n }\n }\n\n document.addEventListener(\"click\", onDocumentClick);\n document.addEventListener(\"keydown\", onDocumentKeydown);\n\n return () => {\n element.removeEventListener(\"toggle\", onToggle as EventListener);\n document.removeEventListener(\"click\", onDocumentClick);\n document.removeEventListener(\"keydown\", onDocumentKeydown);\n };\n});\n\ninterface PrivateContentSignature {\n Element: HTMLDivElement;\n Args: {\n triggerElement: Cell<HTMLElement>;\n contentId: string;\n isOpen: Cell<boolean>;\n PopoverContent: PopoverBlockParams[\"Content\"];\n };\n Blocks: {\n default: [\n {\n Item: WithBoundArgs<typeof Item, \"toggle\">;\n LinkItem: WithBoundArgs<typeof LinkItem, \"toggle\">;\n Separator: typeof Separator;\n },\n ];\n };\n}\n\nexport interface ContentSignature {\n Element: PrivateContentSignature[\"Element\"];\n Blocks: PrivateContentSignature[\"Blocks\"];\n}\n\nconst Content: TOC<PrivateContentSignature> = <template>\n {{#if @isOpen.current}}\n <@PopoverContent\n id={{@contentId}}\n role=\"menu\"\n aria-labelledby={{@triggerElement.current.id}}\n data-tabster={{TABSTER_CONFIG_CONTENT}}\n tabindex=\"0\"\n {{installContent isOpen=@isOpen triggerElement=@triggerElement}}\n ...attributes\n >\n {{yield\n (hash\n Item=(component Item toggle=@isOpen.toggle)\n LinkItem=(component LinkItem toggle=@isOpen.toggle)\n Separator=Separator\n )\n }}\n </@PopoverContent>\n {{/if}}\n</template>;\n\ninterface PrivateTriggerModifierSignature {\n Element: HTMLElement;\n Args: {\n Named: {\n triggerElement: Cell<HTMLElement>;\n isOpen: Cell<boolean>;\n contentId: string;\n setReference: PopoverBlockParams[\"setReference\"];\n stopPropagation?: boolean;\n preventDefault?: boolean;\n };\n };\n}\n\nexport interface TriggerModifierSignature {\n Element: PrivateTriggerModifierSignature[\"Element\"];\n}\n\nconst trigger = eModifier<PrivateTriggerModifierSignature>(\n (\n element,\n _: [],\n { triggerElement, isOpen, contentId, setReference, stopPropagation, preventDefault },\n ) => {\n element.setAttribute(\"aria-haspopup\", \"menu\");\n\n if (isOpen.current) {\n element.setAttribute(\"aria-controls\", contentId);\n element.setAttribute(\"aria-expanded\", \"true\");\n } else {\n element.removeAttribute(\"aria-controls\");\n element.setAttribute(\"aria-expanded\", \"false\");\n }\n\n setTabsterAttribute(element, TABSTER_CONFIG_TRIGGER);\n\n const onTriggerClick = (event: MouseEvent) => {\n if (stopPropagation) {\n event.stopPropagation();\n }\n\n if (preventDefault) {\n event.preventDefault();\n }\n\n isOpen.toggle();\n };\n\n element.addEventListener(\"click\", onTriggerClick);\n\n if (!element.id) {\n element.id = `${contentId}__trigger`;\n }\n\n triggerElement.current = element;\n\n setReference(element);\n\n return () => {\n element.removeEventListener(\"click\", onTriggerClick);\n };\n },\n);\n\ninterface PrivateTriggerSignature {\n Element: HTMLButtonElement;\n Args: {\n triggerModifier: WithBoundArgs<\n typeof trigger,\n \"triggerElement\" | \"contentId\" | \"isOpen\" | \"setReference\"\n >;\n stopPropagation?: boolean;\n preventDefault?: boolean;\n };\n Blocks: { default: [] };\n}\n\nexport interface TriggerSignature {\n Element: PrivateTriggerSignature[\"Element\"];\n Blocks: PrivateTriggerSignature[\"Blocks\"];\n}\n\nconst Trigger: TOC<PrivateTriggerSignature> = <template>\n <button\n type=\"button\"\n {{@triggerModifier stopPropagation=@stopPropagation preventDefault=@preventDefault}}\n ...attributes\n >\n {{yield}}\n </button>\n</template>;\n\nconst IsOpen = () => cell<boolean>(false);\nconst TriggerElement = () => cell<HTMLElement>();\n\nexport class Menu extends Component<Signature> {\n contentId = guidFor(this);\n\n <template>\n {{#let (IsOpen) (TriggerElement) as |isOpen triggerEl|}}\n <Popover\n @flipOptions={{@flipOptions}}\n @middleware={{@middleware}}\n @offsetOptions={{@offsetOptions}}\n @placement={{@placement}}\n @shiftOptions={{@shiftOptions}}\n @strategy={{@strategy}}\n as |p|\n >\n {{#let\n (modifier\n trigger\n triggerElement=triggerEl\n isOpen=isOpen\n contentId=this.contentId\n setReference=p.setReference\n )\n as |triggerModifier|\n }}\n {{yield\n (hash\n trigger=triggerModifier\n Trigger=(component Trigger triggerModifier=triggerModifier)\n Content=(component\n Content\n PopoverContent=p.Content\n isOpen=isOpen\n triggerElement=triggerEl\n contentId=this.contentId\n )\n arrow=p.arrow\n isOpen=isOpen.current\n )\n }}\n {{/let}}\n </Popover>\n {{/let}}\n </template>\n}\n\nexport default Menu;\n"],"names":["TABSTER_CONFIG_CONTENT","getTabsterAttribute","mover","direction","MoverDirections","Both","cyclic","deloser","TABSTER_CONFIG_TRIGGER","Separator","setComponentTemplate","precompileTemplate","strictMode","templateOnly","focusOnHover","e","item","currentTarget","HTMLElement","focus","Item","scope","on","LinkItem","Link","installContent","eModifier","element","_","isOpen","triggerElement","onToggle","newState","tabster","getTabster","window","firstFocusable","focusable","findFirst","container","addEventListener","onDocumentClick","current","target","contains","onDocumentKeydown","key","preventDefault","document","removeEventListener","Content","hash","trigger","contentId","setReference","stopPropagation","setAttribute","removeAttribute","setTabsterAttribute","onTriggerClick","event","toggle","id","Trigger","IsOpen","cell","TriggerElement","Menu","Component","guidFor","Popover"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export { O as OTP, a as OTPInput } from '../otp-H5a4B4yu.js';
1
+ export { O as OTP, a as OTPInput } from '../otp-C8c1EIw6.js';
2
2
  //# sourceMappingURL=one-time-password.js.map
@@ -1,2 +1,2 @@
1
- export { R as Rating } from '../rating-BrIiwDLw.js';
1
+ export { R as Rating } from '../rating-CKWhrr-L.js';
2
2
  //# sourceMappingURL=rating.js.map
@@ -23,6 +23,11 @@ class ThumbComponent extends Component {
23
23
  // When using tick values, the `input` needs the internal index.
24
24
  return this.args.thumb?.inputValue ?? this.args.value ?? this.args.store.internalMin;
25
25
  }
26
+ /** With tick values the input holds an index, which means nothing when read aloud. */
27
+ get valueText() {
28
+ const tick = this.args.store.tickValues?.[this.value];
29
+ return tick === undefined ? undefined : String(tick);
30
+ }
26
31
  get isActive() {
27
32
  return this.args.store.activeThumbIndex === this.index;
28
33
  }
@@ -57,7 +62,7 @@ class ThumbComponent extends Component {
57
62
  this.args.store.handleThumbActivate(this.index);
58
63
  };
59
64
  static {
60
- setComponentTemplate(precompileTemplate("<input ...attributes class=\"ember-primitives__slider__thumb-input\" type=\"range\" min={{@store.internalMin}} max={{@store.internalMax}} step={{@store.internalStep}} value={{this.value}} disabled={{@store.disabled}} data-active={{if this.isActive \"\"}} {{on \"gotpointercapture\" this.onGotPointerCapture}} {{on \"pointerup\" this.onPointerUp}} {{on \"focus\" this.onFocus}} {{on \"input\" this.onInput}} {{on \"change\" this.onChange}} />\n<span class=\"ember-primitives__slider__thumb\" style={{this.positionStyle}} data-active={{if this.isActive \"\"}} data-disabled={{if @store.disabled \"\"}} aria-hidden=\"true\">{{yield}}</span>", {
65
+ setComponentTemplate(precompileTemplate("<input aria-valuetext={{this.valueText}} ...attributes class=\"ember-primitives__slider__thumb-input\" type=\"range\" min={{@store.internalMin}} max={{@store.internalMax}} step={{@store.internalStep}} value={{this.value}} disabled={{@store.disabled}} data-active={{if this.isActive \"\"}} {{on \"gotpointercapture\" this.onGotPointerCapture}} {{on \"pointerup\" this.onPointerUp}} {{on \"focus\" this.onFocus}} {{on \"input\" this.onInput}} {{on \"change\" this.onChange}} />\n<span class=\"ember-primitives__slider__thumb\" style={{this.positionStyle}} data-active={{if this.isActive \"\"}} data-disabled={{if @store.disabled \"\"}} aria-hidden=\"true\">{{yield}}</span>", {
61
66
  strictMode: true,
62
67
  scope: () => ({
63
68
  on
@@ -24,7 +24,7 @@ class Checkbox extends Component {
24
24
  }
25
25
  };
26
26
  static {
27
- setComponentTemplate(precompileTemplate("<input id={{@id}} type=\"checkbox\" role=\"switch\" checked={{@checked.current}} aria-checked={{@checked.current}} data-state={{if @checked.current \"on\" \"off\"}} {{on \"click\" this.handleClick}} ...attributes />", {
27
+ setComponentTemplate(precompileTemplate("<input id={{@id}} type=\"checkbox\" role=\"switch\" checked={{@checked.current}} data-state={{if @checked.current \"on\" \"off\"}} {{on \"click\" this.handleClick}} ...attributes />", {
28
28
  strictMode: true,
29
29
  scope: () => ({
30
30
  on
@@ -1 +1 @@
1
- {"version":3,"file":"switch.js","sources":["../../src/components/-private/typed-elements.gts","../../src/components/switch.gts"],"sourcesContent":["import type { TOC } from \"@ember/component/template-only\";\n\nexport const Div: TOC<{ Element: HTMLDivElement; Blocks: { default: [] } }> = <template>\n <div ...attributes>{{yield}}</div>\n</template>;\n\nexport const Label: TOC<{\n Element: HTMLLabelElement;\n Args: { for: string };\n Blocks: { default: [] };\n}> = <template>\n <label for={{@for}} ...attributes>{{yield}}</label>\n</template>;\n","import Component from \"@glimmer/component\";\nimport { hash } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\n\nimport { cell } from \"ember-resources\";\n\nimport { uniqueId } from \"../utils.ts\";\nimport { Label } from \"./-private/typed-elements.gts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type { WithBoundArgs } from \"@glint/template\";\n\nexport interface Signature {\n Element: HTMLInputElement;\n Args: {\n /**\n * The initial checked value of the Switch.\n * This value is reactive, so if the value that\n * `@checked` is set to updates, the state of the Switch will also update.\n */\n checked?: boolean;\n /**\n * Callback when the Switch state is toggled\n */\n onChange?: (checked: boolean, event: Event) => void;\n };\n Blocks: {\n default?: [\n {\n /**\n * The current state of the Switch.\n *\n * ```gjs\n * import { Switch } from 'ember-primitives/components/switch';\n *\n * <template>\n * <Switch as |s|>\n * {{s.isChecked}}\n * </Switch>\n * </template>\n * ```\n */\n isChecked: boolean;\n /**\n * The Switch Element.\n * It has a pre-wired `id` so that the relevant Label is\n * appropriately associated via the `for` property of the Label.\n *\n * ```gjs\n * import { Switch } from 'ember-primitives/components/switch';\n *\n * <template>\n * <Switch as |s|>\n * <s.Control />\n * </Switch>\n * </template>\n * ```\n */\n Control: WithBoundArgs<typeof Checkbox, \"checked\" | \"id\" | \"onChange\">;\n /**\n * The Switch element requires a label, and this label already has\n * the association to the Control by setting the `for` attribute to the `id` of the Control\n *\n * ```gjs\n * import { Switch } from 'ember-primitive/components/switchs';\n *\n * <template>\n * <Switch as |s|>\n * <s.Label />\n * </Switch>\n * </template>\n * ```\n */\n Label: WithBoundArgs<typeof Label, \"for\">;\n },\n ];\n };\n}\n\ninterface ControlSignature {\n Element: HTMLInputElement;\n Args: {\n id: string;\n checked?: ReturnType<typeof cell<boolean>>;\n onChange?: (checked: boolean, event: Event) => void;\n };\n}\n\nclass Checkbox extends Component<ControlSignature> {\n handleClick = (event: Event) => {\n const newChecked = (event.target as HTMLInputElement).checked;\n\n if (this.args.onChange) {\n this.args.onChange(newChecked, event);\n } else {\n this.args.checked?.toggle();\n }\n };\n\n <template>\n <input\n id={{@id}}\n type=\"checkbox\"\n role=\"switch\"\n checked={{@checked.current}}\n aria-checked={{@checked.current}}\n data-state={{if @checked.current \"on\" \"off\"}}\n {{on \"click\" this.handleClick}}\n ...attributes\n />\n </template>\n}\n\nfunction defaultFalse(value: unknown) {\n return value ?? false;\n}\n\n/**\n * @public\n */\nexport const Switch: TOC<Signature> = <template>\n <div ...attributes data-prim-switch>\n {{#let (uniqueId) as |id|}}\n {{#let (cell (defaultFalse @checked)) as |checked|}}\n {{! @glint-nocheck }}\n {{yield\n (hash\n isChecked=checked.current\n Control=(component Checkbox checked=checked id=id onChange=@onChange)\n Label=(component Label for=id)\n )\n }}\n {{/let}}\n {{/let}}\n </div>\n</template>;\n\nexport default Switch;\n"],"names":["precompileTemplate","strictMode","templateOnly","Label","Checkbox","Component","handleClick","event","newChecked","target","checked","args","onChange","toggle","setComponentTemplate","scope","on","defaultFalse","value","Switch","uniqueId","cell","hash"],"mappings":";;;;;;;;;qBAE8EA,kBAAA,CAAA,oCAAA,EAE9E;EAAAC,UAAA,EAAA;AAAU,CAAA,CAAA,EAAAC,YAAA,EAAA;AAEH,MAAMC,6BAIRH,kBAAA,CAAA,qDAAA,EAEL;EAAAC,UAAA,EAAA;AAAU,CAAA,CAAA,EAAAC,YAAA,EAAA,CAAA;;AC4EV,MAAME,iBAAiBC,SAAA,CAAU;EAC/BC,WAAA,GAAeC,KAAO,IAAA;AACpB,IAAA,MAAMC,aAAcD,KAAA,CAAME,MAAM,CAAsBC,OAAO;AAE7D,IAAA,IAAI,IAAI,CAACC,IAAI,CAACC,QAAQ,EAAE;MACtB,IAAI,CAACD,IAAI,CAACC,QAAQ,CAACJ,UAAA,EAAYD,KAAA,CAAA;AACjC,IAAA,CAAA,MAAO;AACL,MAAA,IAAI,CAACI,IAAI,CAACD,OAAO,EAAEG,MAAA,EAAA;AACrB,IAAA;EACF,CAAA;AAEA,EAAA;IAAAC,oBAAA,CAAAd,kBAAA,CAAA,yNAAA,EAWA;MAAAC,UAAA,EAAA,IAAA;AAAAc,MAAAA,KAAA,EAAAA,OAAA;AAAAC,QAAAA;AAAA,OAAA;KAAU,CAAA,EAAV,IAAW,CAAA;AAAD;AACZ;AAEA,SAASC,YAAAA,CAAaC,KAAc,EAAA;EAClC,OAAOA,KAAA,IAAS,KAAA;AAClB;AAEA;;AAEC;MACYC,MAAY,GAAAL,oBAAA,CAAad,kBAAA,CAAA,yVAAA,EAetC;EAAAC,UAAA,EAAA,IAAA;AAAAc,EAAAA,KAAA,EAAAA,OAAA;IAAAK,QAAA;IAAAC,IAAA;IAAAJ,YAAA;IAAAK,IAAA;IAAAlB,QAAA;AAAAD,IAAAA;AAAA,GAAA;AAAU,CAAA,CAAA,EAAAD,YAAA,EAAA;;;;"}
1
+ {"version":3,"file":"switch.js","sources":["../../src/components/-private/typed-elements.gts","../../src/components/switch.gts"],"sourcesContent":["import type { TOC } from \"@ember/component/template-only\";\n\nexport const Div: TOC<{ Element: HTMLDivElement; Blocks: { default: [] } }> = <template>\n <div ...attributes>{{yield}}</div>\n</template>;\n\nexport const Label: TOC<{\n Element: HTMLLabelElement;\n Args: { for: string };\n Blocks: { default: [] };\n}> = <template>\n <label for={{@for}} ...attributes>{{yield}}</label>\n</template>;\n","import Component from \"@glimmer/component\";\nimport { hash } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\n\nimport { cell } from \"ember-resources\";\n\nimport { uniqueId } from \"../utils.ts\";\nimport { Label } from \"./-private/typed-elements.gts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type { WithBoundArgs } from \"@glint/template\";\n\nexport interface Signature {\n /**\n * The wrapping element.\n * An accessible name belongs on `Control`, or comes from `Label`.\n */\n Element: HTMLDivElement;\n Args: {\n /**\n * The initial checked value of the Switch.\n * This value is reactive, so if the value that\n * `@checked` is set to updates, the state of the Switch will also update.\n */\n checked?: boolean;\n /**\n * Callback when the Switch state is toggled\n */\n onChange?: (checked: boolean, event: Event) => void;\n };\n Blocks: {\n default?: [\n {\n /**\n * The current state of the Switch.\n *\n * ```gjs\n * import { Switch } from 'ember-primitives/components/switch';\n *\n * <template>\n * <Switch as |s|>\n * {{s.isChecked}}\n * </Switch>\n * </template>\n * ```\n */\n isChecked: boolean;\n /**\n * The Switch Element.\n * It has a pre-wired `id` so that the relevant Label is\n * appropriately associated via the `for` property of the Label.\n *\n * ```gjs\n * import { Switch } from 'ember-primitives/components/switch';\n *\n * <template>\n * <Switch as |s|>\n * <s.Control />\n * </Switch>\n * </template>\n * ```\n */\n Control: WithBoundArgs<typeof Checkbox, \"checked\" | \"id\" | \"onChange\">;\n /**\n * The Switch element requires a label, and this label already has\n * the association to the Control by setting the `for` attribute to the `id` of the Control\n *\n * ```gjs\n * import { Switch } from 'ember-primitive/components/switchs';\n *\n * <template>\n * <Switch as |s|>\n * <s.Label />\n * </Switch>\n * </template>\n * ```\n */\n Label: WithBoundArgs<typeof Label, \"for\">;\n },\n ];\n };\n}\n\ninterface ControlSignature {\n Element: HTMLInputElement;\n Args: {\n id: string;\n checked?: ReturnType<typeof cell<boolean>>;\n onChange?: (checked: boolean, event: Event) => void;\n };\n}\n\nclass Checkbox extends Component<ControlSignature> {\n handleClick = (event: Event) => {\n const newChecked = (event.target as HTMLInputElement).checked;\n\n if (this.args.onChange) {\n this.args.onChange(newChecked, event);\n } else {\n this.args.checked?.toggle();\n }\n };\n\n <template>\n <input\n id={{@id}}\n type=\"checkbox\"\n role=\"switch\"\n checked={{@checked.current}}\n data-state={{if @checked.current \"on\" \"off\"}}\n {{on \"click\" this.handleClick}}\n ...attributes\n />\n </template>\n}\n\nfunction defaultFalse(value: unknown) {\n return value ?? false;\n}\n\n/**\n * @public\n */\nexport const Switch: TOC<Signature> = <template>\n <div ...attributes data-prim-switch>\n {{#let (uniqueId) as |id|}}\n {{#let (cell (defaultFalse @checked)) as |checked|}}\n {{! @glint-nocheck }}\n {{yield\n (hash\n isChecked=checked.current\n Control=(component Checkbox checked=checked id=id onChange=@onChange)\n Label=(component Label for=id)\n )\n }}\n {{/let}}\n {{/let}}\n </div>\n</template>;\n\nexport default Switch;\n"],"names":["precompileTemplate","strictMode","templateOnly","Label","Checkbox","Component","handleClick","event","newChecked","target","checked","args","onChange","toggle","setComponentTemplate","scope","on","defaultFalse","value","Switch","uniqueId","cell","hash"],"mappings":";;;;;;;;;qBAE8EA,kBAAA,CAAA,oCAAA,EAE9E;EAAAC,UAAA,EAAA;AAAU,CAAA,CAAA,EAAAC,YAAA,EAAA;AAEH,MAAMC,6BAIRH,kBAAA,CAAA,qDAAA,EAEL;EAAAC,UAAA,EAAA;AAAU,CAAA,CAAA,EAAAC,YAAA,EAAA,CAAA;;ACgFV,MAAME,iBAAiBC,SAAA,CAAU;EAC/BC,WAAA,GAAeC,KAAO,IAAA;AACpB,IAAA,MAAMC,aAAcD,KAAA,CAAME,MAAM,CAAsBC,OAAO;AAE7D,IAAA,IAAI,IAAI,CAACC,IAAI,CAACC,QAAQ,EAAE;MACtB,IAAI,CAACD,IAAI,CAACC,QAAQ,CAACJ,UAAA,EAAYD,KAAA,CAAA;AACjC,IAAA,CAAA,MAAO;AACL,MAAA,IAAI,CAACI,IAAI,CAACD,OAAO,EAAEG,MAAA,EAAA;AACrB,IAAA;EACF,CAAA;AAEA,EAAA;IAAAC,oBAAA,CAAAd,kBAAA,CAAA,uLAAA,EAUA;MAAAC,UAAA,EAAA,IAAA;AAAAc,MAAAA,KAAA,EAAAA,OAAA;AAAAC,QAAAA;AAAA,OAAA;KAAU,CAAA,EAAV,IAAW,CAAA;AAAD;AACZ;AAEA,SAASC,YAAAA,CAAaC,KAAc,EAAA;EAClC,OAAOA,KAAA,IAAS,KAAA;AAClB;AAEA;;AAEC;MACYC,MAAY,GAAAL,oBAAA,CAAad,kBAAA,CAAA,yVAAA,EAetC;EAAAC,UAAA,EAAA,IAAA;AAAAc,EAAAA,KAAA,EAAAA,OAAA;IAAAK,QAAA;IAAAC,IAAA;IAAAJ,YAAA;IAAAK,IAAA;IAAAlB,QAAA;AAAAD,IAAAA;AAAA,GAAA;AAAU,CAAA,CAAA,EAAAD,YAAA,EAAA;;;;"}
@@ -26,21 +26,34 @@ const TABSTER_CONFIG = getTabsterAttribute({
26
26
  mover: {
27
27
  direction: MoverDirections.Both,
28
28
  cyclic: true,
29
+ hasDefault: true,
29
30
  memorizeCurrent: true
30
31
  },
31
32
  deloser: {}
32
33
  }, true);
33
- const TabLink = setComponentTemplate(precompileTemplate("<a href=\"##missing##\" ...attributes role=\"tab\" aria-controls={{@panelId}} id={{@id}}>\n {{yield}}\n</a>", {
34
- strictMode: true
34
+ const TABSTER_SELECTED_TAB = getTabsterAttribute({
35
+ focusable: {
36
+ isDefault: true
37
+ }
38
+ }, true);
39
+ function tabsterFor(isSelected) {
40
+ return isSelected ? TABSTER_SELECTED_TAB : undefined;
41
+ }
42
+ const TabLink = setComponentTemplate(precompileTemplate("<a href=\"##missing##\" ...attributes role=\"tab\" aria-controls={{@panelId}} aria-selected={{String (@state.isActive @id @value)}} id={{@id}}>\n {{yield}}\n</a>", {
43
+ strictMode: true,
44
+ scope: () => ({
45
+ String
46
+ })
35
47
  }), templateOnly());
36
- const TabButton = setComponentTemplate(precompileTemplate("<button ...attributes role=\"tab\" type=\"button\" aria-controls={{@panelId}} aria-selected={{String (@state.isActive @id @value)}} id={{@id}} {{on \"click\" @handleClick}} {{!-- The Types for modifier are wrong --}} {{!-- @glint-expect-error--}} {{(if @state.isAutomatic (modifier on \"focus\" @handleClick))}}>\n {{yield}}\n</button>", {
48
+ const TabButton = setComponentTemplate(precompileTemplate("<button ...attributes role=\"tab\" type=\"button\" aria-controls={{@panelId}} aria-selected={{String (@state.isActive @id @value)}} data-tabster={{tabsterFor (@state.isActive @id @value)}} id={{@id}} {{on \"click\" @handleClick}} {{!-- The Types for modifier are wrong --}} {{!-- @glint-expect-error--}} {{(if @state.isAutomatic (modifier on \"focus\" @handleClick))}}>\n {{yield}}\n</button>", {
37
49
  strictMode: true,
38
50
  scope: () => ({
39
51
  String,
52
+ tabsterFor,
40
53
  on
41
54
  })
42
55
  }), templateOnly());
43
- const TabContent = setComponentTemplate(precompileTemplate("<Portal @to=\"#{{@state.tabpanelId}}\" @append={{true}}>\n {{#if (@state.isActive @tabId)}}\n <div ...attributes role=\"tabpanel\" aria-labelledby={{@tabId}} id={{@id}}>\n {{yield}}\n </div>\n {{/if}}\n</Portal>", {
56
+ const TabContent = setComponentTemplate(precompileTemplate("<Portal @to=\"#{{@state.tabpanelId}}\" @append={{true}}>\n {{#if (@state.isActive @tabId)}}\n <div tabindex=\"0\" ...attributes role=\"tabpanel\" aria-labelledby={{@tabId}} id={{@id}}>\n {{yield}}\n </div>\n {{/if}}\n</Portal>", {
44
57
  strictMode: true,
45
58
  scope: () => ({
46
59
  Portal
@@ -66,7 +79,7 @@ class TabContainer extends Component {
66
79
  return this.args.label ?? this.tabId;
67
80
  }
68
81
  static {
69
- setComponentTemplate(precompileTemplate("{{#if @label}}\n <TabButton @state={{@state}} @id={{this.tabId}} @value={{@value}} @panelId={{this.panelId}} @handleClick={{fn @state.handleChange this.tabId @value}}>\n {{#if (isString @label)}}\n {{@label}}\n {{else}}\n <@label />\n {{/if}}\n </TabButton>\n\n <TabContent @state={{@state}} @id={{this.panelId}} @tabId={{this.tabId}}>\n {{#if @content}}\n {{#if (isString @content)}}\n {{@content}}\n {{else}}\n <@content />\n {{/if}}\n {{else}}\n {{yield}}\n {{/if}}\n </TabContent>\n{{else}}\n {{yield (makeTab (component TabButton state=@state value=@value id=this.tabId panelId=this.panelId handleClick=(fn @state.handleChange this.tabId @value)) (component TabLink state=@state id=this.tabId panelId=this.panelId)) (component TabContent state=@state id=this.panelId tabId=this.tabId)}}\n{{/if}}", {
82
+ setComponentTemplate(precompileTemplate("{{#if @label}}\n <TabButton @state={{@state}} @id={{this.tabId}} @value={{@value}} @panelId={{this.panelId}} @handleClick={{fn @state.handleChange this.tabId @value}}>\n {{#if (isString @label)}}\n {{@label}}\n {{else}}\n <@label />\n {{/if}}\n </TabButton>\n\n <TabContent @state={{@state}} @id={{this.panelId}} @tabId={{this.tabId}}>\n {{#if @content}}\n {{#if (isString @content)}}\n {{@content}}\n {{else}}\n <@content />\n {{/if}}\n {{else}}\n {{yield}}\n {{/if}}\n </TabContent>\n{{else}}\n {{yield (makeTab (component TabButton state=@state value=@value id=this.tabId panelId=this.panelId handleClick=(fn @state.handleChange this.tabId @value)) (component TabLink state=@state value=@value id=this.tabId panelId=this.panelId)) (component TabContent state=@state id=this.panelId tabId=this.tabId)}}\n{{/if}}", {
70
83
  strictMode: true,
71
84
  scope: () => ({
72
85
  TabButton,
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.js","sources":["../../src/components/tabs.gts"],"sourcesContent":["/**\n * References:\n * - https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/tablist_role\n * - https://www.w3.org/WAI/ARIA/apg/patterns/tabs/\n *\n *\n * Keyboard behaviors (optionally) provided by tabster\n */\n\nimport Component from \"@glimmer/component\";\nimport { tracked } from \"@glimmer/tracking\";\nimport { isDestroyed, isDestroying } from \"@ember/destroyable\";\nimport { fn } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\nimport { next } from \"@ember/runloop\";\n\nimport { getTabsterAttribute, MoverDirections } from \"tabster\";\n\nimport { uniqueId } from \"../utils.ts\";\nimport Portal from \"./portal.gts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type Owner from \"@ember/owner\";\nimport type { ComponentLike, WithBoundArgs } from \"@glint/template\";\n\nconst UNSET = Symbol.for(\"ember-primitives:tabs:unset\");\n\nconst TABSTER_CONFIG = getTabsterAttribute(\n {\n mover: {\n direction: MoverDirections.Both,\n cyclic: true,\n memorizeCurrent: true,\n },\n deloser: {},\n },\n true,\n);\n\nconst TabLink: TOC<{\n Element: HTMLAnchorElement;\n Args: {\n /**\n * @internal\n * for linking of aria\n */\n id: string;\n /**\n * @internal\n * for linking of aria\n */\n panelId: string;\n };\n Blocks: { default: [] };\n}> = <template>\n <a href=\"##missing##\" ...attributes role=\"tab\" aria-controls={{@panelId}} id={{@id}}>\n {{yield}}\n </a>\n</template>;\n\nexport type ButtonType = ComponentLike<ButtonSignature>;\nexport interface ButtonSignature {\n Element: HTMLButtonElement;\n Blocks: {\n default: [];\n };\n}\n\nconst TabButton: TOC<{\n Element: HTMLButtonElement;\n Args: {\n /**\n * @internal\n * for linking of aria\n */\n id: string;\n /**\n * @internal\n * for linking of aria\n */\n panelId: string;\n\n /**\n * @internal\n * for managing state\n */\n handleClick: () => void;\n\n /**\n * @internal\n * for managing state\n */\n value: string | undefined;\n\n /**\n * @internal\n */\n state: TabState;\n };\n Blocks: {\n default: [];\n };\n}> = <template>\n <button\n ...attributes\n role=\"tab\"\n type=\"button\"\n aria-controls={{@panelId}}\n aria-selected={{String (@state.isActive @id @value)}}\n id={{@id}}\n {{on \"click\" @handleClick}}\n {{! The Types for modifier are wrong }}\n {{! @glint-expect-error}}\n {{(if @state.isAutomatic (modifier on \"focus\" @handleClick))}}\n >\n {{yield}}\n </button>\n</template>;\n\nexport type ContentType = ComponentLike<ContentSignature>;\nexport interface ContentSignature {\n /**\n * the [role=tabpanel] element\n */\n Element: HTMLDivElement;\n Blocks: {\n default: [];\n };\n}\n\nconst TabContent: TOC<{\n Element: HTMLDivElement;\n Args: {\n /**\n * @internal\n * for linking of aria\n */\n id: string;\n /**\n * @internal\n * for linking of aria\n */\n tabId: string;\n /**\n * @internal\n */\n state: TabState;\n };\n Blocks: {\n default: [];\n };\n}> = <template>\n <Portal @to=\"#{{@state.tabpanelId}}\" @append={{true}}>\n {{#if (@state.isActive @tabId)}}\n <div ...attributes role=\"tabpanel\" aria-labelledby={{@tabId}} id={{@id}}>\n {{yield}}\n </div>\n {{/if}}\n </Portal>\n</template>;\n\nfunction isString(x: unknown): x is string {\n return typeof x === \"string\";\n}\n\nfunction makeTab(tabButton: any, tabLink: any): any {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n tabButton.Link = tabLink;\n\n return tabButton;\n}\n\nexport type ContainerType = ComponentLike<ContainerSignature>;\nexport type ContainerSignature =\n | {\n Blocks: {\n default: [];\n };\n }\n | {\n Args: {\n label: string | ComponentLike;\n content: string | ComponentLike;\n };\n }\n | {\n Args: {\n label: string | ComponentLike;\n };\n Blocks: {\n /**\n * The content for the tab\n */\n default: [];\n };\n };\n\nclass TabContainer extends Component<{\n Args: {\n /**\n * @internal\n */\n state: TabState;\n\n /**\n * When opting for a \"controlled component\",\n * the value will be needed to make sense of the selected tab.\n *\n * The default value used for communication within the Tabs component (and eventually emitted via the @onChange argument) is a unique random id.\n * So while that could still be used for controlling the tabs component, it may be more easy to grok with user-managed values.\n */\n value?: string;\n\n /**\n * optional user-passable label\n */\n label?: string | ComponentLike;\n\n /**\n * optional user-passable content.\n */\n content?: string | ComponentLike;\n };\n Blocks: {\n default: [\n Label: WithBoundArgs<typeof TabButton, \"state\" | \"id\" | \"panelId\" | \"handleClick\" | \"value\">,\n Content: WithBoundArgs<typeof TabContent, \"state\" | \"id\" | \"tabId\">,\n ];\n };\n}> {\n id = `ember-primitives__tab-${uniqueId()}`;\n\n get tabId() {\n return `${this.id}__tab`;\n }\n\n get panelId() {\n return `${this.id}__panel`;\n }\n\n get label() {\n return this.args.label ?? this.tabId;\n }\n\n <template>\n {{#if @label}}\n <TabButton\n @state={{@state}}\n @id={{this.tabId}}\n @value={{@value}}\n @panelId={{this.panelId}}\n @handleClick={{fn @state.handleChange this.tabId @value}}\n >\n {{#if (isString @label)}}\n {{@label}}\n {{else}}\n <@label />\n {{/if}}\n </TabButton>\n\n <TabContent @state={{@state}} @id={{this.panelId}} @tabId={{this.tabId}}>\n {{#if @content}}\n {{#if (isString @content)}}\n {{@content}}\n {{else}}\n <@content />\n {{/if}}\n {{else}}\n {{yield}}\n {{/if}}\n </TabContent>\n {{else}}\n {{yield\n (makeTab\n (component\n TabButton\n state=@state\n value=@value\n id=this.tabId\n panelId=this.panelId\n handleClick=(fn @state.handleChange this.tabId @value)\n )\n (component TabLink state=@state id=this.tabId panelId=this.panelId)\n )\n (component TabContent state=@state id=this.panelId tabId=this.tabId)\n }}\n {{/if}}\n </template>\n}\n\nconst Label: TOC<{\n /**\n * The label wiring (id, aria, etc) are handled for you.\n * If you'd like to use a heading element (h3, etc), place that in the block content\n * when invoking this Label component.\n */\n Element: null;\n Args: {\n /**\n * @internal\n */\n state: TabState;\n };\n Blocks: { default: [] };\n}> = <template>\n <Portal @to=\"#{{@state.labelId}}\">\n {{yield}}\n </Portal>\n</template>;\n\nexport interface Signature {\n /**\n * The wrapping element for the overall Tabs component.\n * This should be used for styling the layout of the tabs.\n */\n Element: HTMLDivElement;\n Args: {\n /**\n * Sets the active tab.\n * If not passed, the first tab will be selected\n */\n activeTab?: string;\n\n /**\n * Optional label for the overall TabList\n */\n label?: string | ComponentLike;\n\n /**\n * When the tab changes, this function will be called.\n * The function receives both the newly selected tab as well as the previous tab.\n *\n * However, if the tabs are not configured with names, these values will be null.\n */\n onChange?: (selectedTab: string, previousTab: string | null) => void;\n\n /**\n * When activationMode is set to \"automatic\", tabs are activated when receiving focus. When set to \"manual\", tabs are activated when clicked (or when \"enter\" is pressed via the keyboard).\n */\n activationMode?: \"automatic\" | \"manual\";\n };\n Blocks: {\n default: [\n Tab: WithBoundArgs<typeof TabContainer, \"state\"> & {\n Label: WithBoundArgs<typeof Label, \"state\">;\n },\n ];\n };\n}\n\n/**\n * We're doing old skool hax with this, so we don't need to care about what the types think, really\n */\nfunction makeAPI(tabContainer: any, labelComponent: any): any {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n tabContainer.Label = labelComponent;\n\n return tabContainer;\n}\n\nimport { buildWaiter } from \"@ember/test-waiters\";\n\nconst stateWaiter = buildWaiter(\"ember-primitives:tabs\");\n\n/**\n * State bucket passed around to all the sub-components.\n *\n * Sort of a \"Context\", but with a bit of prop-drilling (which is more efficient than dom-context)\n */\nclass TabState {\n declare args: {\n activeTab?: string;\n activationMode?: \"automatic\" | \"manual\";\n onChange?: (selected: string, previous: string | null) => void;\n };\n\n @tracked _active: string | null = null;\n\n @tracked _label: string | undefined;\n\n #first: string | null = null;\n id: string;\n labelId: string;\n tabpanelId: string;\n #token: unknown;\n\n constructor(args: { activeTab?: string; onChange?: () => void }) {\n this.args = args;\n\n this.id = `ember-primitives-${uniqueId()}`;\n this.labelId = `${this.id}__label`;\n this.tabpanelId = `${this.id}__tabpanel`;\n }\n\n get activationMode() {\n return this.args.activationMode ?? \"automatic\";\n }\n\n get isAutomatic() {\n return this.activationMode === \"automatic\";\n }\n\n /**\n * This function relies on the fact that during rendering,\n * the first component to be rendered will be first,\n * and it will be the one to set the secret first value,\n * which means all other tabs will not be first.\n *\n */\n isActive = (tabId: string, tabValue: undefined | string) => {\n /**\n * When users pass the @value to a tab, we use that for managing\n * the \"active state\" instead of the DOM ID.\n *\n * NOTE: DOM IDs must be unique across the whole document, but @value\n * does not need to be unqiue.\n * `@value` *should* be unique for the Tabs component though\n */\n const isSelected = (x: string) => {\n if (tabValue) return x === tabValue;\n\n return x === tabId;\n };\n\n if (this.active === UNSET) {\n if (this.#first) return isSelected(this.#first);\n\n this.#first = tabValue ?? tabId;\n this.#token = stateWaiter.beginAsync();\n\n // eslint-disable-next-line ember/no-runloop\n next(() => {\n if (!this.#token) return;\n stateWaiter.endAsync(this.#token);\n if (this._active) return;\n if (isDestroyed(this) || isDestroying(this)) return;\n\n this._label = tabValue ?? tabId;\n });\n\n return true;\n }\n\n return isSelected(this.active);\n };\n\n get active() {\n return this._active ?? this.args.activeTab ?? UNSET;\n }\n\n get activeLabel() {\n /**\n * This is only needed during the first set\n * because we prioritize rendering first, and then updating metadata later\n * (next render)\n *\n * NOTE: this does not mean that the a11y tree is updated later.\n * it is correct on initial render\n */\n if (this._label) {\n return this._label;\n }\n\n if (this.active === UNSET) {\n return \"Pending\";\n }\n\n return this.active;\n }\n\n handleChange = (tabId: string, tabValue: string | undefined) => {\n const previous = this.active;\n const next = tabValue ?? tabId;\n\n // No change, no need to be noisy\n if (next === previous) return;\n\n this._active = this._label = next;\n\n this.args.onChange?.(next, previous === UNSET ? null : previous);\n };\n}\n\nexport class Tabs extends Component<Signature> {\n state: TabState;\n\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n constructor(owner: Owner, args: {}) {\n super(owner, args);\n\n this.state = new TabState(args);\n }\n\n <template>\n <div class=\"ember-primitives__tabs\" ...attributes data-active={{this.state.activeLabel}}>\n {{! This element will be portaled in to and replaced if tabs.Label is invoked }}\n <div class=\"ember-primitives__tabs__label\" id={{this.state.labelId}}>\n {{#if (isString @label)}}\n {{@label}}\n {{else}}\n <@label />\n {{/if}}\n </div>\n <div\n class=\"ember-primitives__tabs__tablist\"\n role=\"tablist\"\n aria-labelledby={{this.state.labelId}}\n data-tabster={{TABSTER_CONFIG}}\n >\n {{yield\n (makeAPI (component TabContainer state=this.state) (component Label state=this.state))\n }}\n </div>\n {{!\n Tab's contents are portaled in to this element\n }}\n <div class=\"ember-primitives__tabs__tabpanel\" id={{this.state.tabpanelId}}></div>\n </div>\n </template>\n}\n"],"names":["UNSET","Symbol","for","TABSTER_CONFIG","getTabsterAttribute","mover","direction","MoverDirections","Both","cyclic","memorizeCurrent","deloser","TabLink","setComponentTemplate","precompileTemplate","strictMode","templateOnly","TabButton","scope","String","on","TabContent","Portal","isString","x","makeTab","tabButton","tabLink","Link","TabContainer","Component","id","uniqueId","tabId","panelId","label","args","fn","Label","makeAPI","tabContainer","labelComponent","stateWaiter","buildWaiter","TabState","g","prototype","tracked","i","labelId","tabpanelId","constructor","activationMode","isAutomatic","isActive","tabValue","isSelected","active","beginAsync","next","endAsync","_active","isDestroyed","isDestroying","_label","activeTab","activeLabel","handleChange","previous","onChange","Tabs","state","owner"],"mappings":"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"}
1
+ {"version":3,"file":"tabs.js","sources":["../../src/components/tabs.gts"],"sourcesContent":["/**\n * References:\n * - https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/tablist_role\n * - https://www.w3.org/WAI/ARIA/apg/patterns/tabs/\n *\n *\n * Keyboard behaviors (optionally) provided by tabster\n */\n\nimport Component from \"@glimmer/component\";\nimport { tracked } from \"@glimmer/tracking\";\nimport { isDestroyed, isDestroying } from \"@ember/destroyable\";\nimport { fn } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\nimport { next } from \"@ember/runloop\";\n\nimport { getTabsterAttribute, MoverDirections } from \"tabster\";\n\nimport { uniqueId } from \"../utils.ts\";\nimport Portal from \"./portal.gts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type Owner from \"@ember/owner\";\nimport type { ComponentLike, WithBoundArgs } from \"@glint/template\";\n\nconst UNSET = Symbol.for(\"ember-primitives:tabs:unset\");\n\nconst TABSTER_CONFIG = getTabsterAttribute(\n {\n mover: {\n direction: MoverDirections.Both,\n cyclic: true,\n hasDefault: true,\n memorizeCurrent: true,\n },\n deloser: {},\n },\n true,\n);\n\nconst TABSTER_SELECTED_TAB = getTabsterAttribute({ focusable: { isDefault: true } }, true);\n\nfunction tabsterFor(isSelected: boolean) {\n return isSelected ? TABSTER_SELECTED_TAB : undefined;\n}\n\nconst TabLink: TOC<{\n Element: HTMLAnchorElement;\n Args: {\n /**\n * @internal\n * for linking of aria\n */\n id: string;\n /**\n * @internal\n * for linking of aria\n */\n panelId: string;\n\n /**\n * @internal\n * for managing state\n */\n value: string | undefined;\n\n /**\n * @internal\n */\n state: TabState;\n };\n Blocks: { default: [] };\n}> = <template>\n <a\n href=\"##missing##\"\n ...attributes\n role=\"tab\"\n aria-controls={{@panelId}}\n aria-selected={{String (@state.isActive @id @value)}}\n id={{@id}}\n >\n {{yield}}\n </a>\n</template>;\n\nexport type ButtonType = ComponentLike<ButtonSignature>;\nexport interface ButtonSignature {\n Element: HTMLButtonElement;\n Blocks: {\n default: [];\n };\n}\n\nconst TabButton: TOC<{\n Element: HTMLButtonElement;\n Args: {\n /**\n * @internal\n * for linking of aria\n */\n id: string;\n /**\n * @internal\n * for linking of aria\n */\n panelId: string;\n\n /**\n * @internal\n * for managing state\n */\n handleClick: () => void;\n\n /**\n * @internal\n * for managing state\n */\n value: string | undefined;\n\n /**\n * @internal\n */\n state: TabState;\n };\n Blocks: {\n default: [];\n };\n}> = <template>\n <button\n ...attributes\n role=\"tab\"\n type=\"button\"\n aria-controls={{@panelId}}\n aria-selected={{String (@state.isActive @id @value)}}\n data-tabster={{tabsterFor (@state.isActive @id @value)}}\n id={{@id}}\n {{on \"click\" @handleClick}}\n {{! The Types for modifier are wrong }}\n {{! @glint-expect-error}}\n {{(if @state.isAutomatic (modifier on \"focus\" @handleClick))}}\n >\n {{yield}}\n </button>\n</template>;\n\nexport type ContentType = ComponentLike<ContentSignature>;\nexport interface ContentSignature {\n /**\n * the [role=tabpanel] element\n */\n Element: HTMLDivElement;\n Blocks: {\n default: [];\n };\n}\n\nconst TabContent: TOC<{\n Element: HTMLDivElement;\n Args: {\n /**\n * @internal\n * for linking of aria\n */\n id: string;\n /**\n * @internal\n * for linking of aria\n */\n tabId: string;\n /**\n * @internal\n */\n state: TabState;\n };\n Blocks: {\n default: [];\n };\n}> = <template>\n <Portal @to=\"#{{@state.tabpanelId}}\" @append={{true}}>\n {{#if (@state.isActive @tabId)}}\n <div tabindex=\"0\" ...attributes role=\"tabpanel\" aria-labelledby={{@tabId}} id={{@id}}>\n {{yield}}\n </div>\n {{/if}}\n </Portal>\n</template>;\n\nfunction isString(x: unknown): x is string {\n return typeof x === \"string\";\n}\n\nfunction makeTab(tabButton: any, tabLink: any): any {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n tabButton.Link = tabLink;\n\n return tabButton;\n}\n\nexport type ContainerType = ComponentLike<ContainerSignature>;\nexport type ContainerSignature =\n | {\n Blocks: {\n default: [];\n };\n }\n | {\n Args: {\n label: string | ComponentLike;\n content: string | ComponentLike;\n };\n }\n | {\n Args: {\n label: string | ComponentLike;\n };\n Blocks: {\n /**\n * The content for the tab\n */\n default: [];\n };\n };\n\nclass TabContainer extends Component<{\n Args: {\n /**\n * @internal\n */\n state: TabState;\n\n /**\n * When opting for a \"controlled component\",\n * the value will be needed to make sense of the selected tab.\n *\n * The default value used for communication within the Tabs component (and eventually emitted via the @onChange argument) is a unique random id.\n * So while that could still be used for controlling the tabs component, it may be more easy to grok with user-managed values.\n */\n value?: string;\n\n /**\n * optional user-passable label\n */\n label?: string | ComponentLike;\n\n /**\n * optional user-passable content.\n */\n content?: string | ComponentLike;\n };\n Blocks: {\n default: [\n Label: WithBoundArgs<\n typeof TabButton,\n \"state\" | \"id\" | \"panelId\" | \"handleClick\" | \"value\"\n > & {\n Link: WithBoundArgs<typeof TabLink, \"state\" | \"value\" | \"id\" | \"panelId\">;\n },\n Content: WithBoundArgs<typeof TabContent, \"state\" | \"id\" | \"tabId\">,\n ];\n };\n}> {\n id = `ember-primitives__tab-${uniqueId()}`;\n\n get tabId() {\n return `${this.id}__tab`;\n }\n\n get panelId() {\n return `${this.id}__panel`;\n }\n\n get label() {\n return this.args.label ?? this.tabId;\n }\n\n <template>\n {{#if @label}}\n <TabButton\n @state={{@state}}\n @id={{this.tabId}}\n @value={{@value}}\n @panelId={{this.panelId}}\n @handleClick={{fn @state.handleChange this.tabId @value}}\n >\n {{#if (isString @label)}}\n {{@label}}\n {{else}}\n <@label />\n {{/if}}\n </TabButton>\n\n <TabContent @state={{@state}} @id={{this.panelId}} @tabId={{this.tabId}}>\n {{#if @content}}\n {{#if (isString @content)}}\n {{@content}}\n {{else}}\n <@content />\n {{/if}}\n {{else}}\n {{yield}}\n {{/if}}\n </TabContent>\n {{else}}\n {{yield\n (makeTab\n (component\n TabButton\n state=@state\n value=@value\n id=this.tabId\n panelId=this.panelId\n handleClick=(fn @state.handleChange this.tabId @value)\n )\n (component TabLink state=@state value=@value id=this.tabId panelId=this.panelId)\n )\n (component TabContent state=@state id=this.panelId tabId=this.tabId)\n }}\n {{/if}}\n </template>\n}\n\nconst Label: TOC<{\n /**\n * The label wiring (id, aria, etc) are handled for you.\n * If you'd like to use a heading element (h3, etc), place that in the block content\n * when invoking this Label component.\n */\n Element: null;\n Args: {\n /**\n * @internal\n */\n state: TabState;\n };\n Blocks: { default: [] };\n}> = <template>\n <Portal @to=\"#{{@state.labelId}}\">\n {{yield}}\n </Portal>\n</template>;\n\nexport interface Signature {\n /**\n * The wrapping element for the overall Tabs component.\n * This should be used for styling the layout of the tabs.\n */\n Element: HTMLDivElement;\n Args: {\n /**\n * Sets the active tab.\n * If not passed, the first tab will be selected\n */\n activeTab?: string;\n\n /**\n * Optional label for the overall TabList\n */\n label?: string | ComponentLike;\n\n /**\n * When the tab changes, this function will be called.\n * The function receives both the newly selected tab as well as the previous tab.\n *\n * However, if the tabs are not configured with names, these values will be null.\n */\n onChange?: (selectedTab: string, previousTab: string | null) => void;\n\n /**\n * When activationMode is set to \"automatic\", tabs are activated when receiving focus. When set to \"manual\", tabs are activated when clicked (or when \"enter\" is pressed via the keyboard).\n */\n activationMode?: \"automatic\" | \"manual\";\n };\n Blocks: {\n default: [\n Tab: WithBoundArgs<typeof TabContainer, \"state\"> & {\n Label: WithBoundArgs<typeof Label, \"state\">;\n },\n ];\n };\n}\n\n/**\n * We're doing old skool hax with this, so we don't need to care about what the types think, really\n */\nfunction makeAPI(tabContainer: any, labelComponent: any): any {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n tabContainer.Label = labelComponent;\n\n return tabContainer;\n}\n\nimport { buildWaiter } from \"@ember/test-waiters\";\n\nconst stateWaiter = buildWaiter(\"ember-primitives:tabs\");\n\n/**\n * State bucket passed around to all the sub-components.\n *\n * Sort of a \"Context\", but with a bit of prop-drilling (which is more efficient than dom-context)\n */\nclass TabState {\n declare args: {\n activeTab?: string;\n activationMode?: \"automatic\" | \"manual\";\n onChange?: (selected: string, previous: string | null) => void;\n };\n\n @tracked _active: string | null = null;\n\n @tracked _label: string | undefined;\n\n #first: string | null = null;\n id: string;\n labelId: string;\n tabpanelId: string;\n #token: unknown;\n\n constructor(args: { activeTab?: string; onChange?: () => void }) {\n this.args = args;\n\n this.id = `ember-primitives-${uniqueId()}`;\n this.labelId = `${this.id}__label`;\n this.tabpanelId = `${this.id}__tabpanel`;\n }\n\n get activationMode() {\n return this.args.activationMode ?? \"automatic\";\n }\n\n get isAutomatic() {\n return this.activationMode === \"automatic\";\n }\n\n /**\n * This function relies on the fact that during rendering,\n * the first component to be rendered will be first,\n * and it will be the one to set the secret first value,\n * which means all other tabs will not be first.\n *\n */\n isActive = (tabId: string, tabValue: undefined | string) => {\n /**\n * When users pass the @value to a tab, we use that for managing\n * the \"active state\" instead of the DOM ID.\n *\n * NOTE: DOM IDs must be unique across the whole document, but @value\n * does not need to be unqiue.\n * `@value` *should* be unique for the Tabs component though\n */\n const isSelected = (x: string) => {\n if (tabValue) return x === tabValue;\n\n return x === tabId;\n };\n\n if (this.active === UNSET) {\n if (this.#first) return isSelected(this.#first);\n\n this.#first = tabValue ?? tabId;\n this.#token = stateWaiter.beginAsync();\n\n // eslint-disable-next-line ember/no-runloop\n next(() => {\n if (!this.#token) return;\n stateWaiter.endAsync(this.#token);\n if (this._active) return;\n if (isDestroyed(this) || isDestroying(this)) return;\n\n this._label = tabValue ?? tabId;\n });\n\n return true;\n }\n\n return isSelected(this.active);\n };\n\n get active() {\n return this._active ?? this.args.activeTab ?? UNSET;\n }\n\n get activeLabel() {\n /**\n * This is only needed during the first set\n * because we prioritize rendering first, and then updating metadata later\n * (next render)\n *\n * NOTE: this does not mean that the a11y tree is updated later.\n * it is correct on initial render\n */\n if (this._label) {\n return this._label;\n }\n\n if (this.active === UNSET) {\n return \"Pending\";\n }\n\n return this.active;\n }\n\n handleChange = (tabId: string, tabValue: string | undefined) => {\n const previous = this.active;\n const next = tabValue ?? tabId;\n\n // No change, no need to be noisy\n if (next === previous) return;\n\n this._active = this._label = next;\n\n this.args.onChange?.(next, previous === UNSET ? null : previous);\n };\n}\n\nexport class Tabs extends Component<Signature> {\n state: TabState;\n\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n constructor(owner: Owner, args: {}) {\n super(owner, args);\n\n this.state = new TabState(args);\n }\n\n <template>\n <div class=\"ember-primitives__tabs\" ...attributes data-active={{this.state.activeLabel}}>\n {{! This element will be portaled in to and replaced if tabs.Label is invoked }}\n <div class=\"ember-primitives__tabs__label\" id={{this.state.labelId}}>\n {{#if (isString @label)}}\n {{@label}}\n {{else}}\n <@label />\n {{/if}}\n </div>\n <div\n class=\"ember-primitives__tabs__tablist\"\n role=\"tablist\"\n aria-labelledby={{this.state.labelId}}\n data-tabster={{TABSTER_CONFIG}}\n >\n {{yield\n (makeAPI (component TabContainer state=this.state) (component Label state=this.state))\n }}\n </div>\n {{!\n Tab's contents are portaled in to this element\n }}\n <div class=\"ember-primitives__tabs__tabpanel\" id={{this.state.tabpanelId}}></div>\n </div>\n </template>\n}\n"],"names":["UNSET","Symbol","for","TABSTER_CONFIG","getTabsterAttribute","mover","direction","MoverDirections","Both","cyclic","hasDefault","memorizeCurrent","deloser","TABSTER_SELECTED_TAB","focusable","isDefault","tabsterFor","isSelected","undefined","TabLink","setComponentTemplate","precompileTemplate","strictMode","scope","String","templateOnly","TabButton","on","TabContent","Portal","isString","x","makeTab","tabButton","tabLink","Link","TabContainer","Component","id","uniqueId","tabId","panelId","label","args","fn","Label","makeAPI","tabContainer","labelComponent","stateWaiter","buildWaiter","TabState","g","prototype","tracked","i","labelId","tabpanelId","constructor","activationMode","isAutomatic","isActive","tabValue","active","beginAsync","next","endAsync","_active","isDestroyed","isDestroying","_label","activeTab","activeLabel","handleChange","previous","onChange","Tabs","state","owner"],"mappings":"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"}
@@ -26,7 +26,6 @@
26
26
  gap: var(--zoetrope-gap, 8px);
27
27
  overflow: scroll visible;
28
28
  padding: 8px var(--zoetrope-offset, 0);
29
- scroll-behavior: smooth;
30
29
  scroll-padding-left: var(--zoetrope-offset, 0);
31
30
  scroll-snap-type: x mandatory;
32
31
  scrollbar-color: transparent transparent;
@@ -38,3 +37,9 @@
38
37
  scroll-snap-align: start;
39
38
  }
40
39
  }
40
+
41
+ @media (prefers-reduced-motion: no-preference) {
42
+ .ember-primitives__zoetrope__scroller {
43
+ scroll-behavior: smooth;
44
+ }
45
+ }
@@ -1,2 +1,2 @@
1
- export { Z as Zoetrope, Z as default } from '../index-gRO4Cvlf.js';
1
+ export { Z as Zoetrope, Z as default } from '../index-B-yrfUe9.js';
2
2
  //# sourceMappingURL=zoetrope.js.map
@@ -89,7 +89,6 @@ class Zoetrope extends Component {
89
89
  if (!shiftKey && !nextElement || shiftKey && !previousElement) {
90
90
  return;
91
91
  }
92
- event.preventDefault();
93
92
  let newTarget = null;
94
93
  if (shiftKey) {
95
94
  newTarget = previousElement;
@@ -99,9 +98,14 @@ class Zoetrope extends Component {
99
98
  if (!newTarget) {
100
99
  return;
101
100
  }
102
- newTarget?.focus({
101
+ newTarget.focus({
103
102
  preventScroll: true
104
103
  });
104
+ /** Cancelling Tab when the sibling cannot take focus traps the keyboard. */
105
+ if (target.getRootNode().activeElement !== newTarget) {
106
+ return;
107
+ }
108
+ event.preventDefault();
105
109
  const rect = getRelativeBoundingClientRect(newTarget, this.scrollerElement);
106
110
  this.scrollerElement?.scrollBy({
107
111
  left: rect.left,
@@ -130,6 +134,9 @@ class Zoetrope extends Component {
130
134
  if (macroCondition(isTesting())) {
131
135
  return "instant";
132
136
  }
137
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
138
+ return "instant";
139
+ }
133
140
  return this.args.scrollBehavior || "smooth";
134
141
  }
135
142
  scrollLeft = () => {
@@ -266,4 +273,4 @@ function getRelativeBoundingClientRect(childElement, parentElement) {
266
273
  }
267
274
 
268
275
  export { Zoetrope as Z };
269
- //# sourceMappingURL=index-gRO4Cvlf.js.map
276
+ //# sourceMappingURL=index-B-yrfUe9.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-B-yrfUe9.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
package/dist/index.js CHANGED
@@ -12,12 +12,12 @@ export { Key, KeyCombo } from './components/keys.js';
12
12
  export { StickyFooter } from './components/layout/sticky-footer.js';
13
13
  export { Link } from './components/link.js';
14
14
  export { Menu } from './components/menu.js';
15
- export { O as OTP, a as OTPInput } from './otp-H5a4B4yu.js';
15
+ export { O as OTP, a as OTPInput } from './otp-C8c1EIw6.js';
16
16
  export { Popover } from './components/popover.js';
17
17
  export { Portal } from './components/portal.js';
18
18
  export { TARGETS as PORTALS, PortalTargets } from './components/portal-targets.js';
19
19
  export { Progress } from './components/progress.js';
20
- export { R as Rating } from './rating-BrIiwDLw.js';
20
+ export { R as Rating } from './rating-CKWhrr-L.js';
21
21
  export { Resizable, Handle as ResizableHandle, Panel as ResizablePanel } from './components/resizable.js';
22
22
  export { Scroller } from './components/scroller.js';
23
23
  export { Separator } from './components/separator.js';
@@ -27,7 +27,7 @@ export { Switch } from './components/switch.js';
27
27
  export { Toggle } from './components/toggle.js';
28
28
  export { ToggleGroup } from './components/toggle-group.js';
29
29
  export { VisuallyHidden } from './components/visually-hidden.js';
30
- export { Z as Zoetrope } from './index-gRO4Cvlf.js';
30
+ export { Z as Zoetrope } from './index-B-yrfUe9.js';
31
31
  export { link } from './helpers/link.js';
32
32
  export { service } from './helpers/service.js';
33
33
 
@@ -34,12 +34,22 @@ function handlePaste(event) {
34
34
  // we want to split the pasted value across
35
35
  // multiple text fields
36
36
  event.preventDefault();
37
- const value = clipboardData.getData('Text');
38
- const digits = value;
37
+ fillFrom(target, clipboardData.getData('Text'));
38
+
39
+ // Selected again, so that another paste gives the same result.
40
+ target.select();
41
+
42
+ // A cancelled paste fires no input event, and @onChange listens for that event.
43
+ target.dispatchEvent(new InputEvent('input', {
44
+ bubbles: true,
45
+ inputType: 'insertFromPaste'
46
+ }));
47
+ }
48
+ function fillFrom(target, code) {
39
49
  let i = 0;
40
50
  let currElement = target;
41
51
  while (currElement) {
42
- currElement.value = digits[i++] || '';
52
+ currElement.value = code[i++] || '';
43
53
  const next = nextInput(currElement);
44
54
  if (next instanceof HTMLInputElement) {
45
55
  currElement = next;
@@ -47,11 +57,6 @@ function handlePaste(event) {
47
57
  break;
48
58
  }
49
59
  }
50
-
51
- // We want to select the first field again
52
- // so that if someone holds paste, or
53
- // pastes again, they get the same result.
54
- target.select();
55
60
  }
56
61
  function handleNavigation(event) {
57
62
  switch (event.key) {
@@ -111,14 +116,21 @@ function previousInput(current) {
111
116
  }
112
117
  const autoAdvance = event => {
113
118
  assert('[BUG]: autoAdvance called on non-input element', event.target instanceof HTMLInputElement);
119
+ if ('inputType' in event && event.inputType === 'insertFromPaste') return;
114
120
  const value = event.target.value;
115
121
  if (value.length === 0) return;
116
- if (value.length > 0) {
117
- if ('data' in event && event.data && typeof event.data === 'string') {
118
- event.target.value = event.data;
119
- }
120
- return focusRight(event);
122
+ const data = 'data' in event && typeof event.data === 'string' ? event.data : '';
123
+
124
+ // Browser autofill puts the whole code in to the first field.
125
+ if (data.length > 1 || !data && value.length > 1) {
126
+ fillFrom(event.target, data || value);
127
+ event.target.select();
128
+ return;
129
+ }
130
+ if (data) {
131
+ event.target.value = data;
121
132
  }
133
+ return focusRight(event);
122
134
  };
123
135
  function getCollectiveValue(elementTarget, length) {
124
136
  if (!elementTarget) return;
@@ -155,7 +167,7 @@ function labelFor(inputIndex, labelFn) {
155
167
  return `Please enter OTP character ${inputIndex + 1}`;
156
168
  }
157
169
  const waiter$1 = buildWaiter("ember-primitives:OTPInput:handleChange");
158
- const Fields = setComponentTemplate(precompileTemplate("{{#each @fields as |_field i|}}\n <label>\n <span class=\"ember-primitives__sr-only\">{{labelFor i @labelFn}}</span>\n <input name=\"code{{i}}\" type=\"text\" inputmode=\"numeric\" autocomplete=\"off\" ...attributes {{on \"click\" selectAll}} {{on \"paste\" handlePaste}} {{on \"input\" autoAdvance}} {{on \"input\" @handleChange}} {{on \"keydown\" handleNavigation}} />\n </label>\n{{/each}}", {
170
+ const Fields = setComponentTemplate(precompileTemplate("{{#each @fields as |_field i|}}\n <label>\n <span class=\"ember-primitives__sr-only\">{{labelFor i @labelFn}}</span>\n <input name=\"code{{i}}\" type=\"text\" inputmode=\"numeric\" autocomplete=\"one-time-code\" ...attributes {{on \"click\" selectAll}} {{on \"paste\" handlePaste}} {{on \"input\" autoAdvance}} {{on \"input\" @handleChange}} {{on \"keydown\" handleNavigation}} />\n </label>\n{{/each}}", {
159
171
  strictMode: true,
160
172
  scope: () => ({
161
173
  labelFor,
@@ -287,4 +299,4 @@ const OTP = setComponentTemplate(precompileTemplate("<form {{on \"submit\" (fn h
287
299
  }), templateOnly());
288
300
 
289
301
  export { OTP as O, OTPInput as a };
290
- //# sourceMappingURL=otp-H5a4B4yu.js.map
302
+ //# sourceMappingURL=otp-C8c1EIw6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otp-C8c1EIw6.js","sources":["../src/components/one-time-password/utils.ts","../src/components/one-time-password/input.gts","../src/components/one-time-password/buttons.gts","../src/components/one-time-password/otp.gts"],"sourcesContent":["import { assert } from '@ember/debug';\n\nfunction getInputs(current: HTMLInputElement) {\n const fieldset = current.closest('fieldset');\n\n assert('[BUG]: fieldset went missing', fieldset);\n\n return [...fieldset.querySelectorAll('input')];\n}\n\nfunction nextInput(current: HTMLInputElement) {\n const inputs = getInputs(current);\n const currentIndex = inputs.indexOf(current);\n\n return inputs[currentIndex + 1];\n}\n\nexport function selectAll(event: Event) {\n const target = event.target;\n\n assert(`selectAll is only meant for use with input elements`, target instanceof HTMLInputElement);\n\n target.select();\n}\n\nexport function handlePaste(event: Event) {\n const target = event.target;\n\n assert(\n `handlePaste is only meant for use with input elements`,\n target instanceof HTMLInputElement\n );\n\n const clipboardData = (event as ClipboardEvent).clipboardData;\n\n assert(\n `Could not get clipboardData while handling the paste event on OTP. Please report this issue on the ember-primitives repo with a reproduction. Thanks!`,\n clipboardData\n );\n\n // This is typically not good to prevent paste.\n // But because of the UX we're implementing,\n // we want to split the pasted value across\n // multiple text fields\n event.preventDefault();\n\n fillFrom(target, clipboardData.getData('Text'));\n\n // Selected again, so that another paste gives the same result.\n target.select();\n\n // A cancelled paste fires no input event, and @onChange listens for that event.\n target.dispatchEvent(new InputEvent('input', { bubbles: true, inputType: 'insertFromPaste' }));\n}\n\nfunction fillFrom(target: HTMLInputElement, code: string) {\n let i = 0;\n let currElement: HTMLInputElement | null = target;\n\n while (currElement) {\n currElement.value = code[i++] || '';\n\n const next = nextInput(currElement);\n\n if (next instanceof HTMLInputElement) {\n currElement = next;\n } else {\n break;\n }\n }\n}\n\nexport function handleNavigation(event: KeyboardEvent) {\n switch (event.key) {\n case 'Backspace':\n return handleBackspace(event);\n case 'ArrowLeft':\n return focusLeft(event);\n case 'ArrowRight':\n return focusRight(event);\n }\n}\n\nfunction focusLeft(event: Pick<Event, 'target'>) {\n const target = event.target;\n\n assert(`only allowed on input elements`, target instanceof HTMLInputElement);\n\n const input = previousInput(target);\n\n input?.focus();\n requestAnimationFrame(() => {\n input?.select();\n });\n}\n\nfunction focusRight(event: Pick<Event, 'target'>) {\n const target = event.target;\n\n assert(`only allowed on input elements`, target instanceof HTMLInputElement);\n\n const input = nextInput(target);\n\n input?.focus();\n requestAnimationFrame(() => {\n input?.select();\n });\n}\n\nconst syntheticEvent = new InputEvent('input');\n\nfunction handleBackspace(event: KeyboardEvent) {\n if (event.key !== 'Backspace') return;\n\n /**\n * We have to prevent default because we\n * - want to clear the whole field\n * - have the focus behavior keep up with the key-repeat\n * speed of the user's computer\n */\n event.preventDefault();\n\n const target = event.target;\n\n if (target && 'value' in target) {\n if (target.value === '') {\n focusLeft({ target });\n } else {\n target.value = '';\n }\n }\n\n target?.dispatchEvent(syntheticEvent);\n}\n\nfunction previousInput(current: HTMLInputElement) {\n const inputs = getInputs(current);\n const currentIndex = inputs.indexOf(current);\n\n return inputs[currentIndex - 1];\n}\n\nexport const autoAdvance = (event: Event) => {\n assert(\n '[BUG]: autoAdvance called on non-input element',\n event.target instanceof HTMLInputElement\n );\n\n if ('inputType' in event && event.inputType === 'insertFromPaste') return;\n\n const value = event.target.value;\n\n if (value.length === 0) return;\n\n const data = 'data' in event && typeof event.data === 'string' ? event.data : '';\n\n // Browser autofill puts the whole code in to the first field.\n if (data.length > 1 || (!data && value.length > 1)) {\n fillFrom(event.target, data || value);\n event.target.select();\n\n return;\n }\n\n if (data) {\n event.target.value = data;\n }\n\n return focusRight(event);\n};\n\nexport function getCollectiveValue(elementTarget: EventTarget | null, length: number) {\n if (!elementTarget) return;\n\n assert(\n `[BUG]: somehow the element target is not HTMLElement`,\n elementTarget instanceof HTMLElement\n );\n\n let parent: null | HTMLElement | ShadowRoot;\n\n // TODO: should this logic be extracted?\n // why is getting the target element within a shadow root hard?\n if (!(elementTarget instanceof HTMLInputElement)) {\n if (elementTarget.shadowRoot) {\n parent = elementTarget.shadowRoot;\n } else {\n parent = elementTarget.closest('fieldset');\n }\n } else {\n parent = elementTarget.closest('fieldset');\n }\n\n assert(`[BUG]: somehow the input fields were rendered without a parent element`, parent);\n\n const elements = parent.querySelectorAll('input');\n\n let value = '';\n\n assert(\n `found elements (${elements.length}) do not match length (${length}). Was the same OTP input rendered more than once?`,\n elements.length === length\n );\n\n for (const element of elements) {\n assert(\n '[BUG]: how did the queried elements become a non-input element?',\n element instanceof HTMLInputElement\n );\n value += element.value;\n }\n\n return value;\n}\n","import Component from \"@glimmer/component\";\nimport { warn } from \"@ember/debug\";\nimport { isDestroyed, isDestroying } from \"@ember/destroyable\";\nimport { on } from \"@ember/modifier\";\nimport { buildWaiter } from \"@ember/test-waiters\";\n\nimport {\n autoAdvance,\n getCollectiveValue,\n handleNavigation,\n handlePaste,\n selectAll,\n} from \"./utils.ts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type { WithBoundArgs } from \"@glint/template\";\n\nconst DEFAULT_LENGTH = 6;\n\nfunction labelFor(inputIndex: number, labelFn: undefined | ((index: number) => string)) {\n if (labelFn) {\n return labelFn(inputIndex);\n }\n\n return `Please enter OTP character ${inputIndex + 1}`;\n}\n\nconst waiter = buildWaiter(\"ember-primitives:OTPInput:handleChange\");\n\nconst Fields: TOC<{\n /**\n * Any attributes passed to this component will be applied to each input.\n */\n Element: HTMLInputElement;\n Args: {\n fields: unknown[];\n labelFn: (index: number) => string;\n handleChange: (event: Event) => void;\n };\n}> = <template>\n {{#each @fields as |_field i|}}\n <label>\n <span class=\"ember-primitives__sr-only\">{{labelFor i @labelFn}}</span>\n <input\n name=\"code{{i}}\"\n type=\"text\"\n inputmode=\"numeric\"\n autocomplete=\"one-time-code\"\n ...attributes\n {{on \"click\" selectAll}}\n {{on \"paste\" handlePaste}}\n {{on \"input\" autoAdvance}}\n {{on \"input\" @handleChange}}\n {{on \"keydown\" handleNavigation}}\n />\n </label>\n {{/each}}\n</template>;\n\nexport class OTPInput extends Component<{\n /**\n * The collection of individual OTP inputs are contained by a fieldset.\n * Applying the `disabled` attribute to this fieldset will disable\n * all of the inputs, if that's desired.\n */\n Element: HTMLFieldSetElement;\n Args: {\n /**\n * How many characters the one-time-password field should be\n * Defaults to 6\n */\n length?: number;\n\n /**\n * To Customize the label of the input fields, you may pass a function.\n * By default, this is `Please enter OTP character ${index + 1}`.\n */\n labelFn?: (index: number) => string;\n\n /**\n * If passed, this function will be called when the <Input> changes.\n * All fields are considered one input.\n */\n onChange?: (\n data: {\n /**\n * The text from the collective `<Input>`\n *\n * `code` _may_ be shorter than `length`\n * if the user has not finished typing / pasting their code\n */\n code: string;\n /**\n * will be `true` if `code`'s length matches the passed `@length` or the default of 6\n */\n complete: boolean;\n },\n /**\n * The last input event received\n */\n event: Event,\n ) => void;\n };\n Blocks: {\n /**\n * Optionally, you may control how the Fields are rendered, with proceeding text,\n * additional attributes added, etc.\n *\n * This is how you can add custom validation to each input field.\n */\n default?: [fields: WithBoundArgs<typeof Fields, \"fields\" | \"handleChange\" | \"labelFn\">];\n };\n}> {\n /**\n * This is debounced, because we bind to each input,\n * but only want to emit one change event if someone pastes\n * multiple characters\n */\n handleChange = (event: Event) => {\n if (!this.args.onChange) return;\n\n if (!this.#token) {\n this.#token = waiter.beginAsync();\n }\n\n if (this.#frame) {\n cancelAnimationFrame(this.#frame);\n }\n\n // We use requestAnimationFrame to be friendly to rendering.\n // We don't know if onChange is going to want to cause paints\n // (it's also how we debounce, under the assumption that \"paste\" behavior\n // would be fast enough to be quicker than individual frames\n // (see logic in autoAdvance)\n // )\n this.#frame = requestAnimationFrame(() => {\n waiter.endAsync(this.#token);\n\n if (isDestroyed(this) || isDestroying(this)) return;\n if (!this.args.onChange) return;\n\n const value = getCollectiveValue(event.target, this.length);\n\n if (value === undefined) {\n warn(`Value could not be determined for the OTP field. was it removed from the DOM?`, {\n id: \"ember-primitives.OTPInput.missing-value\",\n });\n\n return;\n }\n\n this.args.onChange({ code: value, complete: value.length === this.length }, event);\n });\n };\n\n #token: unknown;\n #frame: number | undefined;\n\n get length() {\n return this.args.length ?? DEFAULT_LENGTH;\n }\n\n get fields() {\n // We only need to iterate a number of times,\n // so we don't care about the actual value or\n // referential integrity here\n return new Array<undefined>(this.length);\n }\n\n <template>\n <fieldset ...attributes>\n {{#let\n (component Fields fields=this.fields handleChange=this.handleChange labelFn=@labelFn)\n as |CurriedFields|\n }}\n {{#if (has-block)}}\n {{yield CurriedFields}}\n {{else}}\n <CurriedFields />\n {{/if}}\n {{/let}}\n\n <style>\n .ember-primitives__sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n }\n </style>\n </fieldset>\n </template>\n}\n","import { assert } from \"@ember/debug\";\nimport { on } from \"@ember/modifier\";\n\nimport type { TOC } from \"@ember/component/template-only\";\n\nconst reset = (event: Event) => {\n assert(\"[BUG]: reset called without an event.target\", event.target instanceof HTMLElement);\n\n const form = event.target.closest(\"form\");\n\n assert(\n \"Form is missing. Cannot use <Reset> without being contained within a <form>\",\n form instanceof HTMLFormElement,\n );\n\n form.reset();\n};\n\nexport const Submit: TOC<{\n Element: HTMLButtonElement;\n Blocks: { default: [] };\n}> = <template>\n <button type=\"submit\" ...attributes>Submit</button>\n</template>;\n\nexport const Reset: TOC<{\n Element: HTMLButtonElement;\n Blocks: { default: [] };\n}> = <template>\n <button type=\"button\" {{on \"click\" reset}} ...attributes>{{yield}}</button>\n</template>;\n","import { assert } from \"@ember/debug\";\nimport { fn, hash } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\nimport { buildWaiter } from \"@ember/test-waiters\";\n\nimport { Reset, Submit } from \"./buttons.gts\";\nimport { OTPInput } from \"./input.gts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type { WithBoundArgs } from \"@glint/template\";\n\nconst waiter = buildWaiter(\"ember-primitives:OTP:handleAutoSubmitAttempt\");\n\nconst handleFormSubmit = (submit: (data: { code: string }) => void, event: SubmitEvent) => {\n event.preventDefault();\n\n assert(\n \"[BUG]: handleFormSubmit was not attached to a form. Please open an issue.\",\n event.currentTarget instanceof HTMLFormElement,\n );\n\n const formData = new FormData(event.currentTarget);\n\n let code = \"\";\n\n for (const [key, value] of formData.entries()) {\n if (key.startsWith(\"code\")) {\n // eslint-disable-next-line @typescript-eslint/restrict-plus-operands, @typescript-eslint/no-base-to-string\n code += value;\n }\n }\n\n submit({\n code,\n });\n};\n\nfunction handleChange(\n autoSubmit: boolean | undefined,\n data: { code: string; complete: boolean },\n event: Event,\n) {\n if (!autoSubmit) return;\n if (!data.complete) return;\n\n assert(\n \"[BUG]: event target is not a known element type\",\n event.target instanceof HTMLElement || event.target instanceof SVGElement,\n );\n\n const form = event.target.closest(\"form\");\n\n assert(\"[BUG]: Cannot handle event when <OTP> Inputs are not rendered within their <form>\", form);\n\n const token = waiter.beginAsync();\n const finished = () => {\n waiter.endAsync(token);\n form.removeEventListener(\"submit\", finished);\n };\n\n form.addEventListener(\"submit\", finished);\n\n // NOTE: when calling .submit() the submit event handlers are not run\n form.requestSubmit();\n}\n\nexport const OTP: TOC<{\n /**\n * The overall OTP Input is in its own form.\n * Modern UI/UX Patterns usually have this sort of field\n * as its own page, thus within its own form.\n *\n * By default, only the 'submit' event is bound, and is\n * what calls the `@onSubmit` argument.\n */\n Element: HTMLFormElement;\n Args: {\n /**\n * How many characters the one-time-password field should be\n * Defaults to 6\n */\n length?: number;\n\n /**\n * The on submit callback will give you the entered\n * one-time-password code.\n *\n * It will be called when the user manually clicks the 'submit'\n * button or when the full code is pasted and meats the validation\n * criteria.\n */\n onSubmit: (data: { code: string }) => void;\n\n /**\n * Whether or not to auto-submit after the code has been pasted\n * in to the collective \"field\". Default is false\n */\n autoSubmit?: boolean;\n };\n Blocks: {\n default: [\n {\n /**\n * The collective input field that the OTP code will be typed/pasted in to\n */\n Input: WithBoundArgs<typeof OTPInput, \"length\" | \"onChange\">;\n /**\n * Button with `type=\"submit\"` to submit the form\n */\n Submit: typeof Submit;\n /**\n * Pre-wired button to reset the form\n */\n Reset: typeof Reset;\n },\n ];\n };\n}> = <template>\n <form {{on \"submit\" (fn handleFormSubmit @onSubmit)}} ...attributes>\n {{yield\n (hash\n Input=(component\n OTPInput length=@length onChange=(if @autoSubmit (fn handleChange @autoSubmit))\n )\n Submit=Submit\n Reset=Reset\n )\n }}\n </form>\n</template>;\n"],"names":["getInputs","current","fieldset","closest","assert","querySelectorAll","nextInput","inputs","currentIndex","indexOf","selectAll","event","target","HTMLInputElement","select","handlePaste","clipboardData","preventDefault","fillFrom","getData","dispatchEvent","InputEvent","bubbles","inputType","code","i","currElement","value","next","handleNavigation","key","handleBackspace","focusLeft","focusRight","input","previousInput","focus","requestAnimationFrame","syntheticEvent","autoAdvance","length","data","getCollectiveValue","elementTarget","HTMLElement","parent","shadowRoot","elements","element","DEFAULT_LENGTH","labelFor","inputIndex","labelFn","waiter","buildWaiter","Fields","setComponentTemplate","precompileTemplate","strictMode","scope","on","templateOnly","OTPInput","Component","handleChange","args","onChange","beginAsync","cancelAnimationFrame","endAsync","isDestroyed","isDestroying","undefined","warn","id","complete","fields","Array","reset","form","HTMLFormElement","Submit","Reset","handleFormSubmit","submit","currentTarget","formData","FormData","entries","startsWith","autoSubmit","SVGElement","token","finished","removeEventListener","addEventListener","requestSubmit","OTP","fn","hash"],"mappings":"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"}