@pearpages/pulp-react 0.2.2 → 0.3.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 (156) hide show
  1. package/README.md +14 -0
  2. package/dist/accordion.js +1 -1
  3. package/dist/alert.css +18 -0
  4. package/dist/alert.css.map +1 -1
  5. package/dist/alert.js +4 -4
  6. package/dist/avatar.css +46 -0
  7. package/dist/avatar.css.map +1 -0
  8. package/dist/avatar.d.ts +41 -0
  9. package/dist/avatar.js +5 -0
  10. package/dist/avatar.js.map +1 -0
  11. package/dist/badge.css +37 -0
  12. package/dist/badge.css.map +1 -1
  13. package/dist/badge.d.ts +22 -5
  14. package/dist/badge.js +2 -1
  15. package/dist/button.css +18 -0
  16. package/dist/button.css.map +1 -1
  17. package/dist/button.d.ts +11 -2
  18. package/dist/button.js +2 -2
  19. package/dist/calendar.js +1 -1
  20. package/dist/card.js +2 -2
  21. package/dist/checkbox.js +4 -4
  22. package/dist/chip.css +95 -0
  23. package/dist/chip.css.map +1 -0
  24. package/dist/chip.d.ts +43 -0
  25. package/dist/chip.js +4 -0
  26. package/dist/chip.js.map +1 -0
  27. package/dist/{chunk-N6E2E2OY.js → chunk-2NVC3C7K.js} +3 -3
  28. package/dist/{chunk-N6E2E2OY.js.map → chunk-2NVC3C7K.js.map} +1 -1
  29. package/dist/{chunk-MF66ICX6.js → chunk-56RSH7GQ.js} +3 -3
  30. package/dist/{chunk-MF66ICX6.js.map → chunk-56RSH7GQ.js.map} +1 -1
  31. package/dist/chunk-5TYCIBLW.js +27 -0
  32. package/dist/chunk-5TYCIBLW.js.map +1 -0
  33. package/dist/chunk-7O6FTCZL.js +101 -0
  34. package/dist/chunk-7O6FTCZL.js.map +1 -0
  35. package/dist/{chunk-N4C3NQIN.js → chunk-A7TMFEQ2.js} +3 -3
  36. package/dist/{chunk-N4C3NQIN.js.map → chunk-A7TMFEQ2.js.map} +1 -1
  37. package/dist/{chunk-2NSQPN7S.js → chunk-AZAI4OVR.js} +3 -3
  38. package/dist/{chunk-2NSQPN7S.js.map → chunk-AZAI4OVR.js.map} +1 -1
  39. package/dist/{chunk-DVZ46GQN.js → chunk-CLE2QGCU.js} +3 -3
  40. package/dist/{chunk-DVZ46GQN.js.map → chunk-CLE2QGCU.js.map} +1 -1
  41. package/dist/{chunk-5TTYVQ6Q.js → chunk-DE67ECD7.js} +5 -3
  42. package/dist/chunk-DE67ECD7.js.map +1 -0
  43. package/dist/{chunk-BAPNIZDV.js → chunk-F2YI5N4L.js} +3 -3
  44. package/dist/chunk-F2YI5N4L.js.map +1 -0
  45. package/dist/{chunk-U3N3G2UA.js → chunk-FFCEY76B.js} +10 -5
  46. package/dist/chunk-FFCEY76B.js.map +1 -0
  47. package/dist/{chunk-XWPXW46D.js → chunk-GWTHITZO.js} +3 -3
  48. package/dist/{chunk-XWPXW46D.js.map → chunk-GWTHITZO.js.map} +1 -1
  49. package/dist/chunk-HDC2IQV2.js +34 -0
  50. package/dist/chunk-HDC2IQV2.js.map +1 -0
  51. package/dist/{chunk-VQN5DQP6.js → chunk-HKNIEQ2V.js} +4 -4
  52. package/dist/{chunk-VQN5DQP6.js.map → chunk-HKNIEQ2V.js.map} +1 -1
  53. package/dist/{chunk-LA3YBXCR.js → chunk-HPQ462R5.js} +3 -3
  54. package/dist/{chunk-LA3YBXCR.js.map → chunk-HPQ462R5.js.map} +1 -1
  55. package/dist/chunk-KSLKNWWM.js +28 -0
  56. package/dist/chunk-KSLKNWWM.js.map +1 -0
  57. package/dist/chunk-OKA2PLDV.js +85 -0
  58. package/dist/chunk-OKA2PLDV.js.map +1 -0
  59. package/dist/{chunk-6BIEW4WJ.js → chunk-Q6SYKNZ5.js} +3 -3
  60. package/dist/{chunk-6BIEW4WJ.js.map → chunk-Q6SYKNZ5.js.map} +1 -1
  61. package/dist/chunk-QID6YYFF.js +33 -0
  62. package/dist/chunk-QID6YYFF.js.map +1 -0
  63. package/dist/{chunk-ZVDN3GRI.js → chunk-QJG5ILK5.js} +3 -3
  64. package/dist/{chunk-ZVDN3GRI.js.map → chunk-QJG5ILK5.js.map} +1 -1
  65. package/dist/chunk-QXHSA4QD.js +43 -0
  66. package/dist/chunk-QXHSA4QD.js.map +1 -0
  67. package/dist/chunk-S632WN4W.js +106 -0
  68. package/dist/chunk-S632WN4W.js.map +1 -0
  69. package/dist/{chunk-OFFFRIJG.js → chunk-SDIK6VSC.js} +3 -3
  70. package/dist/{chunk-OFFFRIJG.js.map → chunk-SDIK6VSC.js.map} +1 -1
  71. package/dist/{chunk-M5VL22MY.js → chunk-SXMORGSG.js} +3 -3
  72. package/dist/{chunk-M5VL22MY.js.map → chunk-SXMORGSG.js.map} +1 -1
  73. package/dist/{chunk-Z6SS4G4V.js → chunk-UMK4D234.js} +3 -3
  74. package/dist/{chunk-Z6SS4G4V.js.map → chunk-UMK4D234.js.map} +1 -1
  75. package/dist/{chunk-5PYLJQJX.js → chunk-VS2HPJIX.js} +3 -3
  76. package/dist/{chunk-5PYLJQJX.js.map → chunk-VS2HPJIX.js.map} +1 -1
  77. package/dist/{chunk-NOUUOH4R.js → chunk-WDIFWMKE.js} +3 -3
  78. package/dist/chunk-WDIFWMKE.js.map +1 -0
  79. package/dist/chunk-Y7KC2FDU.js +88 -0
  80. package/dist/chunk-Y7KC2FDU.js.map +1 -0
  81. package/dist/{chunk-OFKSU77Y.js → chunk-ZEVQQQOA.js} +3 -3
  82. package/dist/{chunk-OFKSU77Y.js.map → chunk-ZEVQQQOA.js.map} +1 -1
  83. package/dist/combobox.css +3 -0
  84. package/dist/combobox.css.map +1 -1
  85. package/dist/combobox.js +2 -2
  86. package/dist/component-manifest.json +679 -8
  87. package/dist/date-picker.js +1 -1
  88. package/dist/dialog.js +1 -1
  89. package/dist/divider.css +37 -0
  90. package/dist/divider.css.map +1 -0
  91. package/dist/divider.d.ts +35 -0
  92. package/dist/divider.js +4 -0
  93. package/dist/divider.js.map +1 -0
  94. package/dist/empty-state.css +175 -0
  95. package/dist/empty-state.css.map +1 -0
  96. package/dist/empty-state.d.ts +40 -0
  97. package/dist/empty-state.js +7 -0
  98. package/dist/empty-state.js.map +1 -0
  99. package/dist/field.js +2 -2
  100. package/dist/icon-button.css +18 -0
  101. package/dist/icon-button.css.map +1 -1
  102. package/dist/icon-button.js +3 -3
  103. package/dist/index.css +489 -0
  104. package/dist/index.css.map +1 -1
  105. package/dist/index.d.ts +8 -2
  106. package/dist/index.js +38 -32
  107. package/dist/link.css +35 -0
  108. package/dist/link.css.map +1 -0
  109. package/dist/link.d.ts +37 -0
  110. package/dist/link.js +5 -0
  111. package/dist/link.js.map +1 -0
  112. package/dist/listbox.js +1 -1
  113. package/dist/menu.js +2 -2
  114. package/dist/pagination.css +18 -0
  115. package/dist/pagination.css.map +1 -1
  116. package/dist/pagination.js +4 -4
  117. package/dist/picker.css +3 -0
  118. package/dist/picker.css.map +1 -1
  119. package/dist/picker.js +2 -2
  120. package/dist/popover.js +2 -2
  121. package/dist/radio.js +3 -3
  122. package/dist/segmented-control.css +111 -0
  123. package/dist/segmented-control.css.map +1 -0
  124. package/dist/segmented-control.d.ts +90 -0
  125. package/dist/segmented-control.js +5 -0
  126. package/dist/segmented-control.js.map +1 -0
  127. package/dist/select.js +3 -3
  128. package/dist/sheet.css +28 -0
  129. package/dist/sheet.css.map +1 -1
  130. package/dist/sheet.d.ts +9 -2
  131. package/dist/sheet.js +1 -1
  132. package/dist/slider.js +1 -1
  133. package/dist/switch.js +4 -4
  134. package/dist/table.js +1 -1
  135. package/dist/tabs.js +1 -1
  136. package/dist/text-field.css +63 -0
  137. package/dist/text-field.css.map +1 -1
  138. package/dist/text-field.d.ts +15 -2
  139. package/dist/text-field.js +3 -3
  140. package/dist/textarea.js +3 -3
  141. package/dist/toast.css +18 -0
  142. package/dist/toast.css.map +1 -1
  143. package/dist/toast.d.ts +21 -3
  144. package/dist/toast.js +5 -5
  145. package/dist/tooltip.js +2 -2
  146. package/package.json +36 -6
  147. package/dist/chunk-5TTYVQ6Q.js.map +0 -1
  148. package/dist/chunk-737GQSOB.js +0 -19
  149. package/dist/chunk-737GQSOB.js.map +0 -1
  150. package/dist/chunk-BAPNIZDV.js.map +0 -1
  151. package/dist/chunk-IFIQLIA3.js +0 -48
  152. package/dist/chunk-IFIQLIA3.js.map +0 -1
  153. package/dist/chunk-NOUUOH4R.js.map +0 -1
  154. package/dist/chunk-TJJBCS3N.js +0 -28
  155. package/dist/chunk-TJJBCS3N.js.map +0 -1
  156. package/dist/chunk-U3N3G2UA.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/button/Button.module.css","../src/button/Button.tsx"],"names":["button","label"],"mappings":"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","file":"chunk-DE67ECD7.js","sourcesContent":["/*\n * Every value is a token. State is expressed through data attributes so the\n * styling hooks survive a change of styling tool, and so tests and agents can\n * read state off the DOM.\n */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--button-gap);\n min-block-size: var(--button-height-md);\n padding-block: 0;\n padding-inline: var(--button-padding-inline-md);\n border: 1px solid transparent;\n border-radius: var(--button-radius);\n font-family: var(--button-font-family);\n font-size: var(--button-font-size-md);\n font-weight: var(--button-font-weight);\n line-height: 1;\n text-decoration: none;\n white-space: nowrap;\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n transition:\n background-color var(--button-motion-duration) var(--motion-easing-standard),\n border-color var(--button-motion-duration) var(--motion-easing-standard),\n color var(--button-motion-duration) var(--motion-easing-standard);\n\n &:focus-visible {\n outline: var(--button-focus-ring-width) solid var(--button-focus-ring);\n outline-offset: var(--button-focus-ring-offset);\n }\n\n &:disabled,\n &[aria-disabled=\"true\"] {\n cursor: not-allowed;\n opacity: 0.55;\n }\n\n &[data-loading] {\n cursor: progress;\n }\n\n &[data-size=\"sm\"] {\n min-block-size: var(--button-height-sm);\n padding-inline: var(--button-padding-inline-sm);\n font-size: var(--button-font-size-sm);\n }\n\n &[data-size=\"lg\"] {\n min-block-size: var(--button-height-lg);\n padding-inline: var(--button-padding-inline-lg);\n font-size: var(--button-font-size-lg);\n }\n\n &[data-variant=\"primary\"] {\n background-color: var(--button-primary-bg);\n color: var(--button-primary-fg);\n\n &:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--button-primary-bg-hover);\n }\n\n &:active:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--button-primary-bg-active);\n }\n }\n\n &[data-variant=\"secondary\"] {\n background-color: var(--button-secondary-bg);\n border-color: var(--button-secondary-border);\n color: var(--button-secondary-fg);\n\n &:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--button-secondary-bg-hover);\n }\n }\n\n &[data-variant=\"ghost\"] {\n background-color: transparent;\n color: var(--button-ghost-fg);\n\n &:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--button-ghost-bg-hover);\n }\n }\n }\n\n /* tone=\"danger\", after the variants so it wins at equal specificity plus one attribute. */\n .button[data-tone=\"danger\"] {\n &[data-variant=\"primary\"] {\n background-color: var(--button-danger-bg);\n color: var(--button-danger-fg);\n\n &:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--button-danger-bg-hover);\n }\n\n &:active:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--button-danger-bg-active);\n }\n }\n\n &:is([data-variant=\"secondary\"], [data-variant=\"ghost\"]) {\n color: var(--button-danger-text);\n\n &:hover:not(:disabled, [aria-disabled=\"true\"]) {\n background-color: var(--button-danger-quiet-bg-hover);\n }\n }\n }\n\n .label {\n display: inline-block;\n }\n}\n","import { Children, isValidElement, type ButtonHTMLAttributes, type MouseEvent, type ReactNode, type Ref } from 'react';\nimport { Icon } from '../icon';\nimport { renderAsChild } from '../internal/asChild';\nimport { Spinner } from '../spinner';\nimport { classes } from '../internal/classes';\nimport styles from './Button.module.css';\n\nexport type ButtonTone = 'default' | 'danger';\nexport type ButtonVariant = 'primary' | 'secondary' | 'ghost';\nexport type ButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface ButtonProps<E extends HTMLElement = HTMLButtonElement> extends ButtonHTMLAttributes<HTMLButtonElement> {\n /**\n * Visual emphasis. One `primary` per view; `secondary` for the rest;\n * `ghost` for actions that sit inside other content.\n * @default 'primary'\n */\n variant?: ButtonVariant;\n /**\n * `danger` for an action that destroys something (delete, remove, leave). It\n * recolours whichever `variant` is in use, so emphasis and danger stay two\n * separate decisions: `variant=\"ghost\" tone=\"danger\"` is a quiet delete.\n * @default 'default'\n */\n tone?: ButtonTone;\n /** @default 'md' */\n size?: ButtonSize;\n /**\n * Shows a spinner, sets `aria-busy` and `aria-disabled`, and blocks\n * activation. The element stays focusable so focus is not lost mid-action,\n * and the label stays in place so the button keeps its width.\n * @default false\n */\n loading?: boolean;\n /** Decorative element before the label. Hidden from assistive technology. */\n iconStart?: ReactNode;\n /** Decorative element after the label. Hidden from assistive technology. */\n iconEnd?: ReactNode;\n /**\n * Render the single child element instead of a `<button>`, merging the\n * button's props into it. Use it to style a router `<Link>` or an `<a>` as a\n * button. Disabled and loading states then use `aria-disabled`, and the\n * child's own `onClick` does not run while the control is inert.\n * @default false\n */\n asChild?: boolean;\n /**\n * The rendered element. With `asChild` that is the child's element, so pass\n * the type parameter: `<Button<HTMLAnchorElement> asChild ref={anchorRef}>`.\n */\n ref?: Ref<E>;\n children: ReactNode;\n}\n\nconst BLOCK = (event: MouseEvent) => event.preventDefault();\n\nconst DEV = typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production';\n\n/** True when some text exists anywhere in the children tree. */\nfunction hasText(node: ReactNode): boolean {\n return Children.toArray(node).some((child) => {\n if (typeof child === 'string') return child.trim().length > 0;\n if (typeof child === 'number') return true;\n if (isValidElement<{ children?: ReactNode }>(child)) return hasText(child.props.children);\n return false;\n });\n}\n\n/**\n * The one action component. Variants map to emphasis, not colour: one\n * `primary` per view, `secondary` for the rest, `ghost` inside other content.\n * Every value comes from `--button-*` tokens, so a brand restyles it without\n * touching the component. State is exposed as `data-variant`, `data-size` and\n * `data-loading` for styling, tests and agents alike.\n *\n * @status stable\n * @category Actions\n * @accessibility A native `button` (or the child element with `asChild`). `loading` sets `aria-disabled` and `aria-busy` and keeps focus; only `disabled` removes it from the tab order. Icon-only use warns in development: use IconButton, which requires a name.\n * @do One `primary` per view.\n * Use `asChild` for links that look like buttons, keeping the `a` semantics.\n * @do Use `tone=\"danger\"` for the action that destroys, and say what it destroys in the label (\"Delete place\"), since colour alone must not carry it.\n * @dont Use `loading` on a button that is not the one that started the work.\n * Rely on colour to tell variants apart; the label carries the meaning.\n */\nexport function Button<E extends HTMLElement = HTMLButtonElement>({\n variant = 'primary',\n tone = 'default',\n size = 'md',\n loading = false,\n iconStart,\n iconEnd,\n asChild = false,\n className,\n disabled = false,\n type,\n onClick,\n ref,\n children,\n ...rest\n}: ButtonProps<E>) {\n // Inert: must not activate. `disabled` on a real <button> also removes it\n // from the tab order, which is right for \"disabled\" and wrong for \"loading\":\n // the element the user just pressed must keep focus. So loading (and every\n // asChild state) uses aria-disabled and blocks activation in the handler.\n const inert = disabled || loading;\n const nativeDisabled = !asChild && disabled;\n\n if (DEV && !hasText(asChild ? (children as { props?: { children?: ReactNode } }).props?.children : children)) {\n if (!rest['aria-label'] && !rest['aria-labelledby']) {\n console.warn('Button: no text content and no aria-label. Icon-only buttons need an accessible name.');\n }\n }\n\n const props = {\n ...rest,\n ref,\n className: classes(styles.button, className),\n 'data-variant': variant,\n 'data-tone': tone === 'danger' ? tone : undefined,\n 'data-size': size,\n 'data-loading': loading ? '' : undefined,\n 'aria-busy': loading || undefined,\n disabled: nativeDisabled || undefined,\n 'aria-disabled': inert && !nativeDisabled ? true : undefined,\n type: asChild ? undefined : (type ?? 'button'),\n onClick: inert ? BLOCK : onClick,\n };\n\n const decorate = (label: ReactNode) => (\n <>\n {loading && <Spinner decorative size=\"inherit\" tone=\"inherit\" />}\n {iconStart && <Icon size=\"inherit\">{iconStart}</Icon>}\n <span className={styles.label}>{label}</span>\n {iconEnd && <Icon size=\"inherit\">{iconEnd}</Icon>}\n </>\n );\n\n if (asChild) {\n const child = children as { props?: { children?: ReactNode } };\n // The helper merges the forwarded ref with the child's; nothing reads it.\n // eslint-disable-next-line react-hooks/refs -- forwarded, not read\n return renderAsChild('Button', children, { ...props, children: decorate(child.props?.children) }, {\n // An inert control must not run the child's handler either.\n replace: inert ? ['onClick'] : [],\n });\n }\n\n return <button {...(props as ButtonHTMLAttributes<HTMLButtonElement>)}>{decorate(children)}</button>;\n}\n\nButton.displayName = 'Button';\n"]}
@@ -1,5 +1,5 @@
1
- import { renderOption, renderEmpty, listClass } from './chunk-EDTA65L5.js';
2
1
  import { isPresent, AriaFieldLabel, AriaFieldDescription, AriaFieldError, ariaFieldClass } from './chunk-IRNTXAA7.js';
2
+ import { renderOption, renderEmpty, listClass } from './chunk-EDTA65L5.js';
3
3
  import { Icon } from './chunk-O5LII5XP.js';
4
4
  import { Select, Button, SelectValue, Popover, ListBox } from 'react-aria-components';
5
5
  import { ChevronDown } from '@pearpages/pulp-icons';
@@ -63,5 +63,5 @@ function Picker({
63
63
  Picker.displayName = "Picker";
64
64
 
65
65
  export { Picker };
66
- //# sourceMappingURL=chunk-BAPNIZDV.js.map
67
- //# sourceMappingURL=chunk-BAPNIZDV.js.map
66
+ //# sourceMappingURL=chunk-F2YI5N4L.js.map
67
+ //# sourceMappingURL=chunk-F2YI5N4L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/picker/Picker.module.css","../src/picker/Picker.tsx"],"names":["root","trigger","value","chevron","popover","list","AriaSelect","AriaButton","AriaSelectValue","AriaPopover","AriaListBox"],"mappings":";;;;;;;;AAAA,IAAA,cAAA,GAAA;AAAA,EASG,IAAA,EAAAA,aAAAA;AAAA,EAoBA,OAAA,EAAAC,gBAAAA;AAAA,EAkCA,KAAA,EAAAC,cAAAA;AAAA,EAWA,OAAA,EAAAC,gBAAAA;AAAA,EAKA,OAAA,EAAAC,gBAAAA;AAAA,EAUA,IAAA,EAAAC;AAAA,CAAA;AChCI,SAAS,MAAA,CAAO;AAAA,EACrB,KAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA,GAAc,cAAA;AAAA,EACd,YAAA,GAAe,YAAA;AAAA,EACf,IAAA,GAAO,IAAA;AAAA,EACP,QAAA,GAAW,KAAA;AAAA,EACX,QAAA,GAAW,KAAA;AAAA,EACX,IAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAgB;AACd,EAAA,MAAM,OAAA,GAAU,UAAU,KAAK,CAAA;AAC/B,EAAA,uBACE,IAAA;AAAA,IAACC,MAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,cAAA,CAAe,cAAA,CAAO,IAAA,EAAM,SAAS,CAAA;AAAA,MAChD,WAAA,EAAW,IAAA;AAAA,MACX,WAAA,EAAa,KAAA;AAAA,MACb,kBAAA,EAAoB,YAAA;AAAA,MACpB,iBAAA,EAAmB,CAAC,GAAA,KAAQ,QAAA,GAAW,QAAQ,IAAA,GAAO,IAAA,GAAO,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,MACxE,WAAA;AAAA,MACA,UAAA,EAAY,QAAA;AAAA,MACZ,UAAA,EAAY,QAAA;AAAA,MACZ,SAAA,EAAW,OAAA;AAAA,MACX,IAAA;AAAA,MACA,SAAA;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,cAAA,EAAA,EAAe,UAAqB,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,wBAC3C,IAAA,CAACC,MAAA,EAAA,EAAW,GAAA,EAAU,SAAA,EAAW,eAAO,OAAA,EACtC,QAAA,EAAA;AAAA,0BAAA,GAAA,CAACC,WAAA,EAAA,EAAgB,SAAA,EAAW,cAAA,CAAO,KAAA,EAAO,CAAA;AAAA,0BAC1C,GAAA,CAAC,QAAK,IAAA,EAAK,SAAA,EAAU,WAAW,cAAA,CAAO,OAAA,EACrC,QAAA,kBAAA,GAAA,CAAC,WAAA,EAAA,EAAY,CAAA,EACf;AAAA,SAAA,EACF,CAAA;AAAA,wBACA,GAAA,CAAC,wBAAsB,QAAA,EAAA,WAAA,EAAY,CAAA;AAAA,wBACnC,GAAA,CAAC,kBAAgB,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,wBACvB,GAAA,CAACC,WAAY,SAAA,EAAW,cAAA,CAAO,SAAS,SAAA,EAAU,cAAA,EAChD,8BAACC,OAAA,EAAA,EAAY,SAAA,EAAW,UAAU,cAAA,CAAO,IAAI,GAAG,KAAA,EAAc,gBAAA,EAAkB,MAAM,WAAA,CAAY,YAAY,CAAA,EAC3G,QAAA,EAAA,YAAA,EACH,CAAA,EACF;AAAA;AAAA;AAAA,GACF;AAEJ;AAEA,MAAA,CAAO,WAAA,GAAc,QAAA","file":"chunk-F2YI5N4L.js","sourcesContent":["/*\n * Every value is a token (--picker-*); the options read --listbox-*. The\n * trigger is a button drawn like a text field. The popover is positioned by\n * React Aria; the gap is its own padding and --trigger-width (vendor) sizes it.\n */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .root {\n --_height: var(--picker-height-md);\n --_font-size: var(--picker-font-size-md);\n --_border: var(--picker-border-default);\n\n font-family: var(--picker-font-family);\n\n &[data-size=\"sm\"] {\n --_height: var(--picker-height-sm);\n --_font-size: var(--picker-font-size-sm);\n }\n\n &[data-size=\"lg\"] {\n --_height: var(--picker-height-lg);\n --_font-size: var(--picker-font-size-lg);\n }\n\n &[data-invalid] { --_border: var(--picker-border-invalid); }\n }\n\n .trigger {\n display: flex;\n align-items: center;\n gap: var(--picker-gap);\n inline-size: 100%;\n min-block-size: var(--_height);\n padding-block: 0;\n padding-inline: var(--picker-padding-inline);\n border: var(--size-hairline) solid var(--_border);\n border-radius: var(--picker-radius);\n background-color: var(--picker-bg);\n color: var(--picker-fg);\n font-family: inherit;\n font-size: var(--_font-size);\n text-align: start;\n cursor: pointer;\n transition: border-color var(--picker-motion-duration) var(--motion-easing-standard);\n\n &[data-focus-visible] {\n border-color: var(--picker-border-focus);\n outline: var(--picker-focus-ring-width) solid var(--picker-focus-ring);\n outline-offset: var(--picker-focus-ring-offset);\n }\n\n &[data-disabled] {\n cursor: not-allowed;\n opacity: 0.55;\n }\n\n &[data-hovered]:not([data-focus-visible], [data-disabled]) {\n border-color: var(--picker-border-hover);\n }\n }\n\n .value {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n\n &[data-placeholder] {\n color: var(--picker-placeholder);\n }\n }\n\n .chevron {\n flex: none;\n color: var(--picker-icon);\n }\n\n .popover {\n inline-size: var(--trigger-width);\n padding-block-start: var(--picker-gap);\n animation: fade var(--picker-popover-duration) var(--motion-easing-standard);\n\n &[data-placement=\"top\"] {\n padding-block: 0 var(--picker-gap);\n }\n }\n\n .list {\n box-shadow: var(--picker-popover-shadow);\n }\n\n /* The shared list styles paint an inline Listbox's surface; here the list floats. Two classes, so it wins whatever the stylesheet order. */\n .popover .list {\n background-color: var(--picker-popover-bg);\n }\n\n @keyframes fade {\n from {\n opacity: 0;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .popover {\n animation: none;\n }\n }\n}\n","import type { ReactNode, Ref } from 'react';\nimport { Button as AriaButton, ListBox as AriaListBox, Popover as AriaPopover, Select as AriaSelect, SelectValue as AriaSelectValue } from 'react-aria-components';\nimport { ChevronDown } from '@pearpages/pulp-icons';\nimport { Icon } from '../icon';\nimport { AriaFieldDescription, AriaFieldError, AriaFieldLabel, ariaFieldClass, isPresent } from '../internal/AriaField';\nimport { listClass, renderEmpty, renderOption, type ListboxItem } from '../listbox/ListboxOptions';\nimport styles from './Picker.module.css';\n\nexport type PickerItem = ListboxItem;\nexport type PickerSize = 'sm' | 'md' | 'lg';\n\nexport interface PickerProps {\n /** Visible label. Always rendered. */\n label: ReactNode;\n description?: ReactNode;\n /** Presence marks the control invalid and announces the message. */\n error?: ReactNode;\n /** The options. Ids are the values. */\n items: readonly PickerItem[];\n /** Selected id (controlled). `null` is \"nothing selected\". */\n value?: string | null;\n defaultValue?: string | null;\n onChange?: (value: string | null) => void;\n /** Shown in the control until a value is chosen. @default 'Select…' */\n placeholder?: string;\n /** Shown when `items` is empty. @default 'No options' */\n emptyMessage?: ReactNode;\n /** @default 'md' */\n size?: PickerSize;\n /** @default false */\n required?: boolean;\n /** @default false */\n disabled?: boolean;\n /** Submitted with a form through a hidden native select. */\n name?: string;\n autoFocus?: boolean;\n /** Applied to the field wrapper, not the button. */\n className?: string;\n /** The trigger `<button>`. */\n ref?: Ref<HTMLButtonElement>;\n}\n\n/**\n * A single-choice select with rich options (a description line, consistent\n * styling in every browser), on React Aria's select (decision record 001):\n * a button opens a listbox, arrows and typing move, Enter chooses, Escape\n * closes, and a hidden native select carries the value in forms. For a\n * plain list of words, the native `Select` is the default; for several\n * choices at once, use Listbox.\n *\n * @status experimental\n * @category Forms\n * @accessibility A `button` named by the label with `aria-haspopup=\"listbox\"` and `aria-expanded`; the popup is a `listbox` with selected and disabled options; a hidden native select carries `name` and value for forms. Arrows open and move, typing jumps, Enter chooses, Escape closes and returns focus.\n * @do Use a `description` line on options when the label alone is ambiguous.\n * Prefer the native Select for a plain list of words.\n * @dont Use `placeholder` as the only label.\n */\nexport function Picker({\n label,\n description,\n error,\n items,\n value,\n defaultValue,\n onChange,\n placeholder = 'Select…',\n emptyMessage = 'No options',\n size = 'md',\n required = false,\n disabled = false,\n name,\n autoFocus,\n className,\n ref,\n}: PickerProps) {\n const invalid = isPresent(error);\n return (\n <AriaSelect\n className={ariaFieldClass(styles.root, className)}\n data-size={size}\n selectedKey={value}\n defaultSelectedKey={defaultValue}\n onSelectionChange={(key) => onChange?.(key === null ? null : String(key))}\n placeholder={placeholder}\n isRequired={required}\n isDisabled={disabled}\n isInvalid={invalid}\n name={name}\n autoFocus={autoFocus}\n >\n <AriaFieldLabel required={required}>{label}</AriaFieldLabel>\n <AriaButton ref={ref} className={styles.trigger}>\n <AriaSelectValue className={styles.value} />\n <Icon size=\"inherit\" className={styles.chevron}>\n <ChevronDown />\n </Icon>\n </AriaButton>\n <AriaFieldDescription>{description}</AriaFieldDescription>\n <AriaFieldError>{error}</AriaFieldError>\n <AriaPopover className={styles.popover} placement=\"bottom start\">\n <AriaListBox className={listClass(styles.list)} items={items} renderEmptyState={() => renderEmpty(emptyMessage)}>\n {renderOption}\n </AriaListBox>\n </AriaPopover>\n </AriaSelect>\n );\n}\n\nPicker.displayName = 'Picker';\n"]}
@@ -1,5 +1,5 @@
1
- import { Alert } from './chunk-N4C3NQIN.js';
2
- import { Button } from './chunk-5TTYVQ6Q.js';
1
+ import { Alert } from './chunk-A7TMFEQ2.js';
2
+ import { Button } from './chunk-DE67ECD7.js';
3
3
  import { classes } from './chunk-MI4QUKQS.js';
4
4
  import { createContext, useContext, useState, useRef, useEffect, useCallback, useMemo } from 'react';
5
5
  import { createPortal } from 'react-dom';
@@ -19,6 +19,7 @@ var Toast_default = {
19
19
  item: "Toast_item",
20
20
  toast: "Toast_toast"
21
21
  };
22
+ var UNDO_DURATION = 8e3;
22
23
  function ToastProvider({ placement = "bottom-end", max = 5, duration = 6e3, label = "Notifications", children }) {
23
24
  const [items, setItems] = useState([]);
24
25
  const [paused, setPaused] = useState(false);
@@ -98,7 +99,11 @@ function ToastProvider({ placement = "bottom-end", max = 5, duration = 6e3, labe
98
99
  for (const timer of map.values()) if (timer.handle !== void 0) clearTimeout(timer.handle);
99
100
  };
100
101
  }, []);
101
- const value = useMemo(() => ({ toast, dismiss, dismissAll }), [toast, dismiss, dismissAll]);
102
+ const value = useMemo(() => {
103
+ const undo = (message, onUndo, { label: label2 = "Undo", duration: ttl = UNDO_DURATION, ...options } = {}) => toast({ ...options, title: message, duration: ttl, action: { label: label2, onClick: onUndo } });
104
+ const api = Object.assign((options) => toast(options), { undo });
105
+ return { toast: api, dismiss, dismissAll };
106
+ }, [toast, dismiss, dismissAll]);
102
107
  const onKeyDown = (event) => {
103
108
  if (event.key !== "Escape") return;
104
109
  const item = event.target.closest("[data-toast-id]");
@@ -155,5 +160,5 @@ function ToastProvider({ placement = "bottom-end", max = 5, duration = 6e3, labe
155
160
  ToastProvider.displayName = "ToastProvider";
156
161
 
157
162
  export { ToastProvider, useToast };
158
- //# sourceMappingURL=chunk-U3N3G2UA.js.map
159
- //# sourceMappingURL=chunk-U3N3G2UA.js.map
163
+ //# sourceMappingURL=chunk-FFCEY76B.js.map
164
+ //# sourceMappingURL=chunk-FFCEY76B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/toast/context.ts","../src/toast/Toast.module.css","../src/toast/Toast.tsx"],"names":["region","list","item","toast","label"],"mappings":"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","file":"chunk-FFCEY76B.js","sourcesContent":["import { createContext, useContext, type ReactNode } from 'react';\nimport type { AlertTone } from '../alert';\n\nexport interface ToastOptions {\n title: ReactNode;\n description?: ReactNode;\n /** @default 'info' */\n tone?: AlertTone;\n /** Milliseconds before auto-dismiss; `Infinity` keeps it until dismissed. Errors default to `Infinity`. */\n duration?: number;\n /** One button inside the toast. Pressing it runs `onClick` and dismisses the toast. It never takes focus. */\n action?: { label: string; onClick: () => void };\n}\n\nexport interface ToastUndoOptions extends Pick<ToastOptions, 'description' | 'tone'> {\n /** The button's label, for other languages. @default 'Undo' */\n label?: string;\n /** Longer than an ordinary toast by default (8 s): there is something to read, decide and reach. */\n duration?: number;\n}\n\nexport interface ToastFunction {\n /** Shows a toast and returns its id. */\n (options: ToastOptions): string;\n /**\n * The named case for a reversible action: \"Place removed\" with an Undo\n * button. Pressing it runs `onUndo` and dismisses; letting it time out\n * does nothing, so do the work first and undo it on request.\n */\n undo: (message: ReactNode, onUndo: () => void, options?: ToastUndoOptions) => string;\n}\n\nexport interface ToastItem extends ToastOptions {\n id: string;\n}\n\nexport interface ToastContextValue {\n /** Shows a toast and returns its id. `toast.undo(message, onUndo)` is the reversible-action shorthand. */\n toast: ToastFunction;\n dismiss: (id: string) => void;\n dismissAll: () => void;\n}\n\nexport const ToastContext = createContext<ToastContextValue | null>(null);\n\n/** The toast API. Must be used inside `ToastProvider`. */\nexport function useToast(): ToastContextValue {\n const context = useContext(ToastContext);\n if (!context) throw new Error('useToast must be used inside <ToastProvider>');\n return context;\n}\n","/* Every value is a token (--toast-*). The region is fixed; placement is a data attribute. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .region {\n --_top: auto;\n --_end: var(--toast-offset);\n --_bottom: var(--toast-offset);\n --_start: auto;\n\n position: fixed;\n z-index: var(--toast-layer);\n inset: var(--_top) var(--_end) var(--_bottom) var(--_start);\n inline-size: min(var(--toast-width), 100vw);\n padding: 0;\n pointer-events: none;\n\n &[data-placement=\"top-end\"] {\n --_top: var(--toast-offset);\n --_bottom: auto;\n }\n\n &[data-placement=\"top-center\"] {\n --_top: var(--toast-offset);\n --_bottom: auto;\n --_start: 0;\n --_end: 0;\n\n margin-inline: auto;\n }\n }\n\n .list {\n display: flex;\n flex-direction: column;\n gap: var(--toast-gap);\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n .item {\n pointer-events: auto;\n animation: enter var(--toast-motion-duration) var(--motion-easing-standard);\n }\n\n .toast {\n border-radius: var(--toast-radius);\n box-shadow: var(--toast-shadow);\n }\n\n @keyframes enter {\n from {\n opacity: 0;\n translate: 0 var(--space-2);\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .item {\n animation: none;\n }\n }\n}\n","import { useCallback, useEffect, useMemo, useRef, useState, type KeyboardEvent, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Alert } from '../alert';\nimport { Button } from '../button';\nimport { classes } from '../internal/classes';\nimport { ToastContext, type ToastFunction, type ToastItem, type ToastOptions, type ToastUndoOptions } from './context';\n\n/** An undo toast asks for a decision and a reach, so it outlasts the default. */\nconst UNDO_DURATION = 8000;\nimport styles from './Toast.module.css';\n\nexport type ToastPlacement = 'bottom-end' | 'top-end' | 'top-center';\n\nexport interface ToastProviderProps {\n /** @default 'bottom-end' */\n placement?: ToastPlacement;\n /** Most toasts shown at once; the oldest is dismissed first. @default 5 */\n max?: number;\n /** Default auto-dismiss time in milliseconds. @default 6000 */\n duration?: number;\n /** Accessible name of the region. @default 'Notifications' */\n label?: string;\n children: ReactNode;\n}\n\ninterface Timer {\n remaining: number;\n startedAt: number;\n handle: ReturnType<typeof setTimeout> | undefined;\n}\n\n/**\n * Mount once near the app root. Owns a portal element with a polite live\n * region; `useToast()` adds notifications to it. Timers pause while the\n * region is hovered or holds focus, Escape dismisses the focused toast, and\n * error toasts stay until dismissed. Each toast is an Alert.\n * `toast.undo(message, onUndo)` is the shorthand for a reversible action.\n *\n * @status stable\n * @category Feedback\n * @accessibility Owns a `region` named \"Notifications\" with `aria-live=\"polite\"`; each toast is an Alert with its live role off (the region announces). Timers pause while the region is hovered or holds focus; Escape dismisses the focused toast; error toasts stay until dismissed.\n * @do Mount it once near the app root.\n * Keep messages to one sentence; put detail behind an `action`.\n * @dont Use a toast for an error the user must fix in a form; show it at the field.\n * Stack more than a few; the cap drops the oldest.\n */\nexport function ToastProvider({ placement = 'bottom-end', max = 5, duration = 6000, label = 'Notifications', children }: ToastProviderProps) {\n const [items, setItems] = useState<ToastItem[]>([]);\n const [paused, setPaused] = useState(false);\n const timers = useRef(new Map<string, Timer>());\n const counter = useRef(0);\n\n const [container] = useState<HTMLDivElement | undefined>(() => {\n if (typeof document === 'undefined') return undefined;\n const element = document.createElement('div');\n element.dataset.pulpToasts = '';\n return element;\n });\n\n useEffect(() => {\n if (!container) return;\n document.body.append(container);\n return () => container.remove();\n }, [container]);\n\n const dismiss = useCallback((id: string) => {\n const timer = timers.current.get(id);\n if (timer?.handle !== undefined) clearTimeout(timer.handle);\n timers.current.delete(id);\n setItems((current) => current.filter((item) => item.id !== id));\n }, []);\n\n const dismissAll = useCallback(() => {\n for (const timer of timers.current.values()) if (timer.handle !== undefined) clearTimeout(timer.handle);\n timers.current.clear();\n setItems([]);\n }, []);\n\n const start = useCallback(\n (id: string, remaining: number) => {\n if (!Number.isFinite(remaining)) return;\n timers.current.set(id, { remaining, startedAt: Date.now(), handle: setTimeout(() => dismiss(id), remaining) });\n },\n [dismiss],\n );\n\n const toast = useCallback(\n (options: ToastOptions) => {\n counter.current += 1;\n const id = `toast-${counter.current}`;\n const ttl = options.duration ?? (options.tone === 'error' ? Infinity : duration);\n setItems((current) => {\n const next = [...current, { ...options, id }];\n const overflow = next.length - max;\n if (overflow > 0) {\n for (const old of next.slice(0, overflow)) {\n const timer = timers.current.get(old.id);\n if (timer?.handle !== undefined) clearTimeout(timer.handle);\n timers.current.delete(old.id);\n }\n return next.slice(overflow);\n }\n return next;\n });\n if (!paused) start(id, ttl);\n else timers.current.set(id, { remaining: ttl, startedAt: Date.now(), handle: undefined });\n return id;\n },\n [duration, max, paused, start],\n );\n\n // Pause: freeze every timer with its remaining time. Resume: restart them.\n useEffect(() => {\n const map = timers.current;\n if (paused) {\n for (const [id, timer] of map) {\n if (timer.handle === undefined) continue;\n clearTimeout(timer.handle);\n map.set(id, { ...timer, remaining: Math.max(0, timer.remaining - (Date.now() - timer.startedAt)), handle: undefined });\n }\n } else {\n for (const [id, timer] of map) {\n if (timer.handle !== undefined || !Number.isFinite(timer.remaining)) continue;\n map.set(id, { ...timer, startedAt: Date.now(), handle: setTimeout(() => dismiss(id), timer.remaining) });\n }\n }\n }, [paused, dismiss]);\n\n useEffect(() => {\n const map = timers.current;\n return () => {\n for (const timer of map.values()) if (timer.handle !== undefined) clearTimeout(timer.handle);\n };\n }, []);\n\n const value = useMemo(() => {\n const undo = (message: ReactNode, onUndo: () => void, { label = 'Undo', duration: ttl = UNDO_DURATION, ...options }: ToastUndoOptions = {}) =>\n toast({ ...options, title: message, duration: ttl, action: { label, onClick: onUndo } });\n // `toast(options)` and `toast.undo(…)`: a function with a property. The rule sees callbacks that\n // touch refs being handed to a function; Object.assign only copies them, nothing runs during render.\n // eslint-disable-next-line react-hooks/refs -- composed, not called\n const api: ToastFunction = Object.assign((options: ToastOptions) => toast(options), { undo });\n return { toast: api, dismiss, dismissAll };\n }, [toast, dismiss, dismissAll]);\n\n const onKeyDown = (event: KeyboardEvent<HTMLElement>) => {\n if (event.key !== 'Escape') return;\n const item = (event.target as HTMLElement).closest<HTMLElement>('[data-toast-id]');\n if (item?.dataset.toastId) {\n event.preventDefault();\n dismiss(item.dataset.toastId);\n }\n };\n\n const region = (\n <section\n role=\"region\"\n aria-label={label}\n aria-live=\"polite\"\n className={classes(styles.region)}\n data-placement={placement}\n onMouseEnter={() => setPaused(true)}\n onMouseLeave={() => setPaused(false)}\n onFocus={() => setPaused(true)}\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setPaused(false);\n }}\n onKeyDown={onKeyDown}\n >\n <ol className={styles.list}>\n {items.map((item) => (\n <li key={item.id} className={styles.item} data-toast-id={item.id} data-tone={item.tone ?? 'info'}>\n <Alert\n tone={item.tone}\n title={item.title}\n live=\"off\"\n className={styles.toast}\n onDismiss={() => dismiss(item.id)}\n action={\n item.action && (\n <Button\n size=\"sm\"\n variant=\"secondary\"\n onClick={() => {\n item.action?.onClick();\n dismiss(item.id);\n }}\n >\n {item.action.label}\n </Button>\n )\n }\n >\n {item.description}\n </Alert>\n </li>\n ))}\n </ol>\n </section>\n );\n\n return (\n <ToastContext.Provider value={value}>\n {children}\n {container ? createPortal(region, container) : null}\n </ToastContext.Provider>\n );\n}\n\nToastProvider.displayName = 'ToastProvider';\n"]}
@@ -1,5 +1,5 @@
1
1
  import { useFloatingPosition } from './chunk-U6QRAD73.js';
2
- import { renderAsChild } from './chunk-ZVDN3GRI.js';
2
+ import { renderAsChild } from './chunk-QJG5ILK5.js';
3
3
  import { useId, useState, useRef, useCallback, useEffect } from 'react';
4
4
  import { createPortal } from 'react-dom';
5
5
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
@@ -53,5 +53,5 @@ function Tooltip({ content, placement = "top", delay = 300, children }) {
53
53
  Tooltip.displayName = "Tooltip";
54
54
 
55
55
  export { Tooltip };
56
- //# sourceMappingURL=chunk-XWPXW46D.js.map
57
- //# sourceMappingURL=chunk-XWPXW46D.js.map
56
+ //# sourceMappingURL=chunk-GWTHITZO.js.map
57
+ //# sourceMappingURL=chunk-GWTHITZO.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tooltip/Tooltip.module.css","../src/tooltip/Tooltip.tsx"],"names":["tooltip"],"mappings":";;;;;;;AAAA,IAAA,eAAA,GAAA;AAAA,EAKG,OAAA,EAAAA,iBAkBY,CAAA;ACQR,SAAS,OAAA,CAAQ,EAAE,OAAA,EAAS,SAAA,GAAY,OAAO,KAAA,GAAQ,GAAA,EAAK,UAAS,EAAiB;AAC3F,EAAA,MAAM,KAAK,KAAA,EAAM;AACjB,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,KAAK,CAAA;AACtC,EAAA,MAAM,KAAA,GAAQ,OAAsC,MAAS,CAAA;AAC7D,EAAA,MAAM,EAAE,IAAA,EAAM,aAAA,EAAe,SAAA,EAAW,QAAA,KAAa,mBAAA,CAAoB,EAAE,IAAA,EAAM,SAAA,EAAW,CAAA;AAE5F,EAAA,MAAM,IAAA,GAAO,WAAA;AAAA,IACX,CAAC,IAAA,KAAiB;AAChB,MAAA,YAAA,CAAa,MAAM,OAAO,CAAA;AAC1B,MAAA,IAAI,IAAA,KAAS,CAAA,EAAG,OAAA,CAAQ,IAAI,CAAA;AAAA,iBACjB,OAAA,GAAU,UAAA,CAAW,MAAM,OAAA,CAAQ,IAAI,GAAG,IAAI,CAAA;AAAA,IAC3D,CAAA;AAAA,IACA;AAAC,GACH;AACA,EAAA,MAAM,IAAA,GAAO,YAAY,MAAM;AAC7B,IAAA,YAAA,CAAa,MAAM,OAAO,CAAA;AAC1B,IAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,EACf,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM,MAAM,YAAA,CAAa,MAAM,OAAO,CAAA,EAAG,EAAE,CAAA;AACrD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,MAAM,SAAA,GAAY,CAAC,KAAA,KAAyB;AAC1C,MAAA,IAAI,KAAA,CAAM,GAAA,KAAQ,QAAA,EAAU,IAAA,EAAK;AAAA,IACnC,CAAA;AACA,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,SAAS,CAAA;AAC9C,IAAA,OAAO,MAAM,QAAA,CAAS,mBAAA,CAAoB,SAAA,EAAW,SAAS,CAAA;AAAA,EAChE,CAAA,EAAG,CAAC,IAAA,EAAM,IAAI,CAAC,CAAA;AAIf,EAAA,MAAM,OAAA,GAAU,aAAA,CAAc,SAAA,EAAW,QAAA,EAAU;AAAA,IACjD,KAAK,IAAA,CAAK,YAAA;AAAA,IACV,YAAA,EAAc,MAAM,IAAA,CAAK,KAAK,CAAA;AAAA,IAC9B,YAAA,EAAc,IAAA;AAAA,IACd,OAAA,EAAS,MAAM,IAAA,CAAK,CAAC,CAAA;AAAA,IACrB,MAAA,EAAQ,IAAA;AAAA,IACR,kBAAA,EAAoB,OAAO,EAAA,GAAK;AAAA,GACjC,CAAA;AAED,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,IAAA,OAAA;AAAA,IACA,IAAA,IACC,YAAA;AAAA;AAAA,sBAEE,GAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAK,IAAA,CAAK,aAAa,EAAA,EAAQ,IAAA,EAAK,SAAA,EAAU,SAAA,EAAW,gBAAO,OAAA,EAAS,gBAAA,EAAgB,QAAA,EAAU,KAAA,EAAO,eAC5G,QAAA,EAAA,OAAA,EACH,CAAA;AAAA,MACA,QAAA,CAAS;AAAA;AACX,GAAA,EACJ,CAAA;AAEJ;AAEA,OAAA,CAAQ,WAAA,GAAc,SAAA","file":"chunk-XWPXW46D.js","sourcesContent":["/* Every value is a token (--tooltip-*). Position comes in as --_x/--_y from the floating hook. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .tooltip {\n --_gap: var(--tooltip-gap);\n\n position: fixed;\n z-index: var(--tooltip-layer);\n inset-block-start: var(--_y);\n inset-inline-start: var(--_x);\n max-inline-size: var(--tooltip-max-width);\n padding-block: var(--tooltip-padding-block);\n padding-inline: var(--tooltip-padding-inline);\n border-radius: var(--tooltip-radius);\n background-color: var(--tooltip-bg);\n color: var(--tooltip-fg);\n font-family: var(--font-family-body);\n font-size: var(--tooltip-font-size);\n line-height: var(--font-line-height-normal);\n box-shadow: var(--tooltip-shadow);\n pointer-events: none;\n animation: fade var(--tooltip-duration) var(--motion-easing-standard);\n }\n\n @keyframes fade {\n from {\n opacity: 0;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .tooltip {\n animation: none;\n }\n }\n}\n","import { useCallback, useEffect, useId, useRef, useState, type ReactElement, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport { renderAsChild } from '../internal/asChild';\nimport { useFloatingPosition, type FloatingPlacement } from '../internal/floating';\nimport styles from './Tooltip.module.css';\n\nexport type TooltipPlacement = FloatingPlacement;\n\nexport interface TooltipProps {\n /** The tooltip text. Supplementary only: it must not be the control's only name. */\n content: ReactNode;\n /** Preferred side; flips when there is no room. @default 'top' */\n placement?: TooltipPlacement;\n /** Hover delay in milliseconds. Focus shows immediately. @default 300 */\n delay?: number;\n /** The single element that owns the tooltip; it receives the hover, focus and `aria-describedby` wiring. */\n children: ReactElement;\n}\n\n/**\n * A short description shown on hover or focus and linked with\n * `aria-describedby` while visible. Never the only name of a control: use it\n * for extra detail, and give icon-only controls a real label. Escape hides it.\n *\n * @status stable\n * @category Overlays\n * @accessibility Shown on hover after a delay and on focus immediately; the trigger gets `aria-describedby` pointing at the `tooltip` while it is visible; Escape hides it. It is a description, never a name.\n * @do Use it for extra detail on controls that already have a name.\n * @dont Put interactive content in it.\n * Use it to name an icon-only control; use IconButton's `label`.\n */\nexport function Tooltip({ content, placement = 'top', delay = 300, children }: TooltipProps) {\n const id = useId();\n const [open, setOpen] = useState(false);\n const timer = useRef<ReturnType<typeof setTimeout>>(undefined);\n const { refs, positionStyle, placement: resolved } = useFloatingPosition({ open, placement });\n\n const show = useCallback(\n (wait: number) => {\n clearTimeout(timer.current);\n if (wait === 0) setOpen(true);\n else timer.current = setTimeout(() => setOpen(true), wait);\n },\n [],\n );\n const hide = useCallback(() => {\n clearTimeout(timer.current);\n setOpen(false);\n }, []);\n\n useEffect(() => () => clearTimeout(timer.current), []);\n useEffect(() => {\n if (!open) return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') hide();\n };\n document.addEventListener('keydown', onKeyDown);\n return () => document.removeEventListener('keydown', onKeyDown);\n }, [open, hide]);\n\n // The helper merges these handlers with the child's own and forwards the ref.\n // eslint-disable-next-line react-hooks/refs -- forwarded to the reference element, not read\n const trigger = renderAsChild('Tooltip', children, {\n ref: refs.setReference,\n onMouseEnter: () => show(delay),\n onMouseLeave: hide,\n onFocus: () => show(0),\n onBlur: hide,\n 'aria-describedby': open ? id : undefined,\n });\n\n return (\n <>\n {trigger}\n {open &&\n createPortal(\n // eslint-disable-next-line react/forbid-dom-props -- per-instance position (--_x/--_y), see internal/floating.ts\n <div ref={refs.setFloating} id={id} role=\"tooltip\" className={styles.tooltip} data-placement={resolved} style={positionStyle}>\n {content}\n </div>,\n document.body,\n )}\n </>\n );\n}\n\nTooltip.displayName = 'Tooltip';\n"]}
1
+ {"version":3,"sources":["../src/tooltip/Tooltip.module.css","../src/tooltip/Tooltip.tsx"],"names":["tooltip"],"mappings":";;;;;;;AAAA,IAAA,eAAA,GAAA;AAAA,EAKG,OAAA,EAAAA,iBAkBY,CAAA;ACQR,SAAS,OAAA,CAAQ,EAAE,OAAA,EAAS,SAAA,GAAY,OAAO,KAAA,GAAQ,GAAA,EAAK,UAAS,EAAiB;AAC3F,EAAA,MAAM,KAAK,KAAA,EAAM;AACjB,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,KAAK,CAAA;AACtC,EAAA,MAAM,KAAA,GAAQ,OAAsC,MAAS,CAAA;AAC7D,EAAA,MAAM,EAAE,IAAA,EAAM,aAAA,EAAe,SAAA,EAAW,QAAA,KAAa,mBAAA,CAAoB,EAAE,IAAA,EAAM,SAAA,EAAW,CAAA;AAE5F,EAAA,MAAM,IAAA,GAAO,WAAA;AAAA,IACX,CAAC,IAAA,KAAiB;AAChB,MAAA,YAAA,CAAa,MAAM,OAAO,CAAA;AAC1B,MAAA,IAAI,IAAA,KAAS,CAAA,EAAG,OAAA,CAAQ,IAAI,CAAA;AAAA,iBACjB,OAAA,GAAU,UAAA,CAAW,MAAM,OAAA,CAAQ,IAAI,GAAG,IAAI,CAAA;AAAA,IAC3D,CAAA;AAAA,IACA;AAAC,GACH;AACA,EAAA,MAAM,IAAA,GAAO,YAAY,MAAM;AAC7B,IAAA,YAAA,CAAa,MAAM,OAAO,CAAA;AAC1B,IAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,EACf,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM,MAAM,YAAA,CAAa,MAAM,OAAO,CAAA,EAAG,EAAE,CAAA;AACrD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,MAAM,SAAA,GAAY,CAAC,KAAA,KAAyB;AAC1C,MAAA,IAAI,KAAA,CAAM,GAAA,KAAQ,QAAA,EAAU,IAAA,EAAK;AAAA,IACnC,CAAA;AACA,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,SAAS,CAAA;AAC9C,IAAA,OAAO,MAAM,QAAA,CAAS,mBAAA,CAAoB,SAAA,EAAW,SAAS,CAAA;AAAA,EAChE,CAAA,EAAG,CAAC,IAAA,EAAM,IAAI,CAAC,CAAA;AAIf,EAAA,MAAM,OAAA,GAAU,aAAA,CAAc,SAAA,EAAW,QAAA,EAAU;AAAA,IACjD,KAAK,IAAA,CAAK,YAAA;AAAA,IACV,YAAA,EAAc,MAAM,IAAA,CAAK,KAAK,CAAA;AAAA,IAC9B,YAAA,EAAc,IAAA;AAAA,IACd,OAAA,EAAS,MAAM,IAAA,CAAK,CAAC,CAAA;AAAA,IACrB,MAAA,EAAQ,IAAA;AAAA,IACR,kBAAA,EAAoB,OAAO,EAAA,GAAK;AAAA,GACjC,CAAA;AAED,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,IAAA,OAAA;AAAA,IACA,IAAA,IACC,YAAA;AAAA;AAAA,sBAEE,GAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAK,IAAA,CAAK,aAAa,EAAA,EAAQ,IAAA,EAAK,SAAA,EAAU,SAAA,EAAW,gBAAO,OAAA,EAAS,gBAAA,EAAgB,QAAA,EAAU,KAAA,EAAO,eAC5G,QAAA,EAAA,OAAA,EACH,CAAA;AAAA,MACA,QAAA,CAAS;AAAA;AACX,GAAA,EACJ,CAAA;AAEJ;AAEA,OAAA,CAAQ,WAAA,GAAc,SAAA","file":"chunk-GWTHITZO.js","sourcesContent":["/* Every value is a token (--tooltip-*). Position comes in as --_x/--_y from the floating hook. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .tooltip {\n --_gap: var(--tooltip-gap);\n\n position: fixed;\n z-index: var(--tooltip-layer);\n inset-block-start: var(--_y);\n inset-inline-start: var(--_x);\n max-inline-size: var(--tooltip-max-width);\n padding-block: var(--tooltip-padding-block);\n padding-inline: var(--tooltip-padding-inline);\n border-radius: var(--tooltip-radius);\n background-color: var(--tooltip-bg);\n color: var(--tooltip-fg);\n font-family: var(--font-family-body);\n font-size: var(--tooltip-font-size);\n line-height: var(--font-line-height-normal);\n box-shadow: var(--tooltip-shadow);\n pointer-events: none;\n animation: fade var(--tooltip-duration) var(--motion-easing-standard);\n }\n\n @keyframes fade {\n from {\n opacity: 0;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .tooltip {\n animation: none;\n }\n }\n}\n","import { useCallback, useEffect, useId, useRef, useState, type ReactElement, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport { renderAsChild } from '../internal/asChild';\nimport { useFloatingPosition, type FloatingPlacement } from '../internal/floating';\nimport styles from './Tooltip.module.css';\n\nexport type TooltipPlacement = FloatingPlacement;\n\nexport interface TooltipProps {\n /** The tooltip text. Supplementary only: it must not be the control's only name. */\n content: ReactNode;\n /** Preferred side; flips when there is no room. @default 'top' */\n placement?: TooltipPlacement;\n /** Hover delay in milliseconds. Focus shows immediately. @default 300 */\n delay?: number;\n /** The single element that owns the tooltip; it receives the hover, focus and `aria-describedby` wiring. */\n children: ReactElement;\n}\n\n/**\n * A short description shown on hover or focus and linked with\n * `aria-describedby` while visible. Never the only name of a control: use it\n * for extra detail, and give icon-only controls a real label. Escape hides it.\n *\n * @status stable\n * @category Overlays\n * @accessibility Shown on hover after a delay and on focus immediately; the trigger gets `aria-describedby` pointing at the `tooltip` while it is visible; Escape hides it. It is a description, never a name.\n * @do Use it for extra detail on controls that already have a name.\n * @dont Put interactive content in it.\n * Use it to name an icon-only control; use IconButton's `label`.\n */\nexport function Tooltip({ content, placement = 'top', delay = 300, children }: TooltipProps) {\n const id = useId();\n const [open, setOpen] = useState(false);\n const timer = useRef<ReturnType<typeof setTimeout>>(undefined);\n const { refs, positionStyle, placement: resolved } = useFloatingPosition({ open, placement });\n\n const show = useCallback(\n (wait: number) => {\n clearTimeout(timer.current);\n if (wait === 0) setOpen(true);\n else timer.current = setTimeout(() => setOpen(true), wait);\n },\n [],\n );\n const hide = useCallback(() => {\n clearTimeout(timer.current);\n setOpen(false);\n }, []);\n\n useEffect(() => () => clearTimeout(timer.current), []);\n useEffect(() => {\n if (!open) return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') hide();\n };\n document.addEventListener('keydown', onKeyDown);\n return () => document.removeEventListener('keydown', onKeyDown);\n }, [open, hide]);\n\n // The helper merges these handlers with the child's own and forwards the ref.\n // eslint-disable-next-line react-hooks/refs -- forwarded to the reference element, not read\n const trigger = renderAsChild('Tooltip', children, {\n ref: refs.setReference,\n onMouseEnter: () => show(delay),\n onMouseLeave: hide,\n onFocus: () => show(0),\n onBlur: hide,\n 'aria-describedby': open ? id : undefined,\n });\n\n return (\n <>\n {trigger}\n {open &&\n createPortal(\n // eslint-disable-next-line react/forbid-dom-props -- per-instance position (--_x/--_y), see internal/floating.ts\n <div ref={refs.setFloating} id={id} role=\"tooltip\" className={styles.tooltip} data-placement={resolved} style={positionStyle}>\n {content}\n </div>,\n document.body,\n )}\n </>\n );\n}\n\nTooltip.displayName = 'Tooltip';\n"]}
@@ -0,0 +1,34 @@
1
+ import { renderAsChild } from './chunk-QJG5ILK5.js';
2
+ import { classes } from './chunk-MI4QUKQS.js';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ // src/link/Link.module.css
6
+ var Link_default = {
7
+ link: "Link_link"
8
+ };
9
+ function Link({
10
+ tone = "action",
11
+ underline = "always",
12
+ asChild = false,
13
+ className,
14
+ ref,
15
+ children,
16
+ ...rest
17
+ }) {
18
+ const props = {
19
+ ...rest,
20
+ ref,
21
+ className: classes(Link_default.link, className),
22
+ "data-tone": tone,
23
+ "data-underline": underline
24
+ };
25
+ if (asChild) {
26
+ return renderAsChild("Link", children, props);
27
+ }
28
+ return /* @__PURE__ */ jsx("a", { ...rest, ref, className: props.className, "data-tone": tone, "data-underline": underline, children });
29
+ }
30
+ Link.displayName = "Link";
31
+
32
+ export { Link };
33
+ //# sourceMappingURL=chunk-HDC2IQV2.js.map
34
+ //# sourceMappingURL=chunk-HDC2IQV2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/link/Link.module.css","../src/link/Link.tsx"],"names":["link"],"mappings":";;;;;AAAA,IAAA,YAAA,GAAA;AAAA,EAKG,IAAA,EAAAA;AAAA,CAAA;AC+BI,SAAS,IAAA,CAAgD;AAAA,EAC9D,IAAA,GAAO,QAAA;AAAA,EACP,SAAA,GAAY,QAAA;AAAA,EACZ,OAAA,GAAU,KAAA;AAAA,EACV,SAAA;AAAA,EACA,GAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAiB;AACf,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,GAAG,IAAA;AAAA,IACH,GAAA;AAAA,IACA,SAAA,EAAW,OAAA,CAAQ,YAAA,CAAO,IAAA,EAAM,SAAS,CAAA;AAAA,IACzC,WAAA,EAAa,IAAA;AAAA,IACb,gBAAA,EAAkB;AAAA,GACpB;AAEA,EAAA,IAAI,OAAA,EAAS;AAEX,IAAA,OAAO,aAAA,CAAc,MAAA,EAAQ,QAAA,EAAU,KAAK,CAAA;AAAA,EAC9C;AAEA,EAAA,uBACE,GAAA,CAAC,GAAA,EAAA,EAAG,GAAG,IAAA,EAAM,GAAA,EAAoC,SAAA,EAAW,KAAA,CAAM,SAAA,EAAW,WAAA,EAAW,IAAA,EAAM,gBAAA,EAAgB,SAAA,EAC3G,QAAA,EACH,CAAA;AAEJ;AAEA,IAAA,CAAK,WAAA,GAAc,MAAA","file":"chunk-HDC2IQV2.js","sourcesContent":["/* Every value is a token: --link-* in packages/tokens/tokens/component/link.json */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .link {\n border-radius: var(--link-radius);\n color: var(--link-tone-action);\n font-weight: var(--link-weight);\n text-decoration-line: underline;\n text-decoration-thickness: from-font;\n text-underline-offset: 0.2em;\n cursor: pointer;\n transition: color var(--link-duration) var(--motion-easing-standard);\n\n &[data-tone=\"default\"] { color: var(--link-tone-default); }\n &[data-tone=\"muted\"] { color: var(--link-tone-muted); }\n\n &[data-underline=\"hover\"] { text-decoration-line: none; }\n\n &:hover {\n color: var(--link-hover);\n text-decoration-line: underline;\n }\n\n &:focus-visible {\n outline: var(--link-focus-ring-width) solid var(--link-focus-ring-color);\n outline-offset: var(--link-focus-ring-offset);\n }\n\n @media (prefers-reduced-motion: reduce) {\n transition: none;\n }\n }\n}\n","import type { AnchorHTMLAttributes, ReactNode, Ref } from 'react';\nimport { renderAsChild } from '../internal/asChild';\nimport { classes } from '../internal/classes';\nimport styles from './Link.module.css';\n\nexport type LinkTone = 'action' | 'default' | 'muted';\nexport type LinkUnderline = 'always' | 'hover';\n\nexport interface LinkProps<E extends HTMLElement = HTMLAnchorElement> extends AnchorHTMLAttributes<HTMLAnchorElement> {\n /** `action` is the brand's link colour; `default` and `muted` take the text colours. @default 'action' */\n tone?: LinkTone;\n /**\n * `hover` drops the underline until the pointer is over it. Only for links that\n * are obviously links from where they sit (a nav, a footer list). @default 'always'\n */\n underline?: LinkUnderline;\n /** Render the single child instead of an `a`: a router's link component. @default false */\n asChild?: boolean;\n\n ref?: Ref<E>;\n children: ReactNode;\n}\n\n/**\n * A text link. Underlined by default, because colour alone must not be what\n * tells a link from the words around it. With `asChild` the styles and props\n * land on a router's own link, so client-side navigation keeps working.\n *\n * @status experimental\n * @category Typography\n * @accessibility A native `a`: focusable and activated with Enter only when it has an `href` (or the `asChild` element provides one). The focus ring comes from the semantic focus tokens. `underline=\"hover\"` removes the only non-colour cue, so it is for lists of links, never for a link inside a sentence (WCAG 1.4.1).\n * @do Use `asChild` with the router's link: `<Link asChild><NextLink href=\"/feed\">Feed</NextLink></Link>`.\n * @do Write link text that makes sense out of context; screen readers list links on their own.\n * @dont Use it for an action that does not navigate; that is a Button (`variant=\"ghost\"`).\n * @dont Use `underline=\"hover\"` for a link inside running text.\n */\nexport function Link<E extends HTMLElement = HTMLAnchorElement>({\n tone = 'action',\n underline = 'always',\n asChild = false,\n className,\n ref,\n children,\n ...rest\n}: LinkProps<E>) {\n const props = {\n ...rest,\n ref,\n className: classes(styles.link, className),\n 'data-tone': tone,\n 'data-underline': underline,\n };\n\n if (asChild) {\n // eslint-disable-next-line react-hooks/refs -- forwarded, not read\n return renderAsChild('Link', children, props);\n }\n\n return (\n <a {...rest} ref={ref as Ref<HTMLAnchorElement>} className={props.className} data-tone={tone} data-underline={underline}>\n {children}\n </a>\n );\n}\n\nLink.displayName = 'Link';\n"]}
@@ -1,5 +1,5 @@
1
- import { IconButton } from './chunk-MF66ICX6.js';
2
- import { Button } from './chunk-5TTYVQ6Q.js';
1
+ import { IconButton } from './chunk-56RSH7GQ.js';
2
+ import { Button } from './chunk-DE67ECD7.js';
3
3
  import { classes } from './chunk-MI4QUKQS.js';
4
4
  import { ArrowLeft, ArrowRight } from '@pearpages/pulp-icons';
5
5
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -80,5 +80,5 @@ function Pagination({
80
80
  Pagination.displayName = "Pagination";
81
81
 
82
82
  export { Pagination, paginationRange };
83
- //# sourceMappingURL=chunk-VQN5DQP6.js.map
84
- //# sourceMappingURL=chunk-VQN5DQP6.js.map
83
+ //# sourceMappingURL=chunk-HKNIEQ2V.js.map
84
+ //# sourceMappingURL=chunk-HKNIEQ2V.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/pagination/range.ts","../src/pagination/Pagination.module.css","../src/pagination/Pagination.tsx"],"names":["root","list","page","ellipsis"],"mappings":"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","file":"chunk-VQN5DQP6.js","sourcesContent":["export type PaginationItem = number | 'start-ellipsis' | 'end-ellipsis';\n\n/** Which pages to show: boundaries at both ends, siblings around the current page, ellipses for the rest. */\nexport function paginationRange(page: number, count: number, siblings: number, boundaries: number): PaginationItem[] {\n const span = (from: number, to: number) => Array.from({ length: Math.max(0, to - from + 1) }, (_, i) => from + i);\n const total = boundaries * 2 + siblings * 2 + 3;\n if (count <= total) return span(1, count);\n const start = span(1, boundaries);\n const end = span(count - boundaries + 1, count);\n const siblingStart = Math.max(Math.min(page - siblings, count - boundaries - siblings * 2 - 1), boundaries + 2);\n const siblingEnd = Math.min(Math.max(page + siblings, boundaries + siblings * 2 + 2), count - boundaries - 1);\n return [\n ...start,\n ...(siblingStart > boundaries + 2 ? (['start-ellipsis'] as PaginationItem[]) : span(boundaries + 1, boundaries + 1)),\n ...span(siblingStart, siblingEnd),\n ...(siblingEnd < count - boundaries - 1 ? (['end-ellipsis'] as PaginationItem[]) : span(count - boundaries, count - boundaries)),\n ...end,\n ];\n}\n","/* Every value is a token (--pagination-*). The controls are Buttons; this file lays them out. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .root {\n --_size: var(--pagination-ellipsis-size-md);\n --_font-size: var(--pagination-font-size-md);\n\n font-family: var(--pagination-font-family);\n\n &[data-size=\"sm\"] {\n --_size: var(--pagination-ellipsis-size-sm);\n --_font-size: var(--pagination-font-size-sm);\n }\n }\n\n .list {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--pagination-gap);\n padding: 0;\n margin: 0;\n list-style: none;\n }\n\n .page {\n min-inline-size: var(--_size);\n padding-inline: 0;\n font-variant-numeric: tabular-nums;\n }\n\n .ellipsis {\n display: grid;\n place-items: center;\n min-inline-size: var(--_size);\n block-size: var(--_size);\n color: var(--pagination-ellipsis-fg);\n font-size: var(--_font-size);\n }\n}\n","import type { HTMLAttributes, Ref } from 'react';\nimport { ArrowLeft, ArrowRight } from '@pearpages/pulp-icons';\nimport { Button } from '../button';\nimport { IconButton } from '../icon-button';\nimport { classes } from '../internal/classes';\nimport { paginationRange } from './range';\nimport styles from './Pagination.module.css';\n\nexport type PaginationSize = 'sm' | 'md';\nexport interface PaginationProps extends Omit<HTMLAttributes<HTMLElement>, 'onChange'> {\n /** The current page, 1-based. */\n page: number;\n /** Total number of pages. */\n count: number;\n onPageChange?: (page: number) => void;\n /** Pages shown on each side of the current one. @default 1 */\n siblings?: number;\n /** Pages always shown at each end. @default 1 */\n boundaries?: number;\n /** Render pages as links (server-side or router pagination) instead of buttons. */\n getHref?: (page: number) => string;\n /** @default 'md' */\n size?: PaginationSize;\n /** The landmark's name. @default 'Pagination' */\n 'aria-label'?: string;\n /** @default 'Previous page' */\n previousLabel?: string;\n /** @default 'Next page' */\n nextLabel?: string;\n /** Accessible name of a page control. @default (n) => `Page ${n}` */\n pageLabel?: (page: number) => string;\n ref?: Ref<HTMLElement>;\n}\n\n/**\n * Page controls in a `nav` landmark: previous, numbered pages with the\n * current one marked `aria-current=\"page\"`, and next. Distant pages\n * collapse into an ellipsis. Buttons by default; `getHref` renders links so\n * the pages are crawlable and open in new tabs. Built from Button and\n * IconButton, so it needs no keyboard model of its own.\n *\n * @status experimental\n * @category Navigation\n * @accessibility A `nav` landmark named by `aria-label`; the current page carries `aria-current=\"page\"`; previous and next are IconButtons with names; ellipses are hidden from assistive technology. With `getHref` the controls are links.\n * @do Use `getHref` when pages have URLs so they can be opened in new tabs and crawled.\n * Keep `siblings` at 1 on narrow screens.\n * @dont Disable the whole component while a page loads; disable only what cannot be pressed.\n */\nexport function Pagination({\n page,\n count,\n onPageChange,\n siblings = 1,\n boundaries = 1,\n getHref,\n size = 'md',\n 'aria-label': ariaLabel = 'Pagination',\n previousLabel = 'Previous page',\n nextLabel = 'Next page',\n pageLabel = (n) => `Page ${n}`,\n className,\n ref,\n ...rest\n}: PaginationProps) {\n const go = (target: number) => () => onPageChange?.(target);\n\n return (\n <nav {...rest} ref={ref} aria-label={ariaLabel} className={classes(styles.root, className)} data-size={size}>\n <ul className={styles.list}>\n <li>\n {page > 1 && getHref ? (\n <IconButton<HTMLAnchorElement> asChild label={previousLabel} icon={<ArrowLeft />} variant=\"ghost\" size={size} onClick={go(page - 1)}>\n <a href={getHref(page - 1)} />\n </IconButton>\n ) : (\n <IconButton label={previousLabel} icon={<ArrowLeft />} variant=\"ghost\" size={size} disabled={page <= 1} onClick={go(page - 1)} />\n )}\n </li>\n {paginationRange(page, count, siblings, boundaries).map((item) =>\n typeof item === 'number' ? (\n <li key={item}>\n {getHref ? (\n <Button<HTMLAnchorElement>\n asChild\n variant={item === page ? 'primary' : 'ghost'}\n size={size}\n className={styles.page}\n aria-label={pageLabel(item)}\n aria-current={item === page ? 'page' : undefined}\n onClick={go(item)}\n >\n <a href={getHref(item)}>{item}</a>\n </Button>\n ) : (\n <Button\n variant={item === page ? 'primary' : 'ghost'}\n size={size}\n className={styles.page}\n aria-label={pageLabel(item)}\n aria-current={item === page ? 'page' : undefined}\n onClick={go(item)}\n >\n {item}\n </Button>\n )}\n </li>\n ) : (\n <li key={item} className={styles.ellipsis} aria-hidden=\"true\">\n …\n </li>\n ),\n )}\n <li>\n {page < count && getHref ? (\n <IconButton<HTMLAnchorElement> asChild label={nextLabel} icon={<ArrowRight />} variant=\"ghost\" size={size} onClick={go(page + 1)}>\n <a href={getHref(page + 1)} />\n </IconButton>\n ) : (\n <IconButton label={nextLabel} icon={<ArrowRight />} variant=\"ghost\" size={size} disabled={page >= count} onClick={go(page + 1)} />\n )}\n </li>\n </ul>\n </nav>\n );\n}\n\nPagination.displayName = 'Pagination';\n"]}
1
+ {"version":3,"sources":["../src/pagination/range.ts","../src/pagination/Pagination.module.css","../src/pagination/Pagination.tsx"],"names":["root","list","page","ellipsis"],"mappings":"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","file":"chunk-HKNIEQ2V.js","sourcesContent":["export type PaginationItem = number | 'start-ellipsis' | 'end-ellipsis';\n\n/** Which pages to show: boundaries at both ends, siblings around the current page, ellipses for the rest. */\nexport function paginationRange(page: number, count: number, siblings: number, boundaries: number): PaginationItem[] {\n const span = (from: number, to: number) => Array.from({ length: Math.max(0, to - from + 1) }, (_, i) => from + i);\n const total = boundaries * 2 + siblings * 2 + 3;\n if (count <= total) return span(1, count);\n const start = span(1, boundaries);\n const end = span(count - boundaries + 1, count);\n const siblingStart = Math.max(Math.min(page - siblings, count - boundaries - siblings * 2 - 1), boundaries + 2);\n const siblingEnd = Math.min(Math.max(page + siblings, boundaries + siblings * 2 + 2), count - boundaries - 1);\n return [\n ...start,\n ...(siblingStart > boundaries + 2 ? (['start-ellipsis'] as PaginationItem[]) : span(boundaries + 1, boundaries + 1)),\n ...span(siblingStart, siblingEnd),\n ...(siblingEnd < count - boundaries - 1 ? (['end-ellipsis'] as PaginationItem[]) : span(count - boundaries, count - boundaries)),\n ...end,\n ];\n}\n","/* Every value is a token (--pagination-*). The controls are Buttons; this file lays them out. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .root {\n --_size: var(--pagination-ellipsis-size-md);\n --_font-size: var(--pagination-font-size-md);\n\n font-family: var(--pagination-font-family);\n\n &[data-size=\"sm\"] {\n --_size: var(--pagination-ellipsis-size-sm);\n --_font-size: var(--pagination-font-size-sm);\n }\n }\n\n .list {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--pagination-gap);\n padding: 0;\n margin: 0;\n list-style: none;\n }\n\n .page {\n min-inline-size: var(--_size);\n padding-inline: 0;\n font-variant-numeric: tabular-nums;\n }\n\n .ellipsis {\n display: grid;\n place-items: center;\n min-inline-size: var(--_size);\n block-size: var(--_size);\n color: var(--pagination-ellipsis-fg);\n font-size: var(--_font-size);\n }\n}\n","import type { HTMLAttributes, Ref } from 'react';\nimport { ArrowLeft, ArrowRight } from '@pearpages/pulp-icons';\nimport { Button } from '../button';\nimport { IconButton } from '../icon-button';\nimport { classes } from '../internal/classes';\nimport { paginationRange } from './range';\nimport styles from './Pagination.module.css';\n\nexport type PaginationSize = 'sm' | 'md';\nexport interface PaginationProps extends Omit<HTMLAttributes<HTMLElement>, 'onChange'> {\n /** The current page, 1-based. */\n page: number;\n /** Total number of pages. */\n count: number;\n onPageChange?: (page: number) => void;\n /** Pages shown on each side of the current one. @default 1 */\n siblings?: number;\n /** Pages always shown at each end. @default 1 */\n boundaries?: number;\n /** Render pages as links (server-side or router pagination) instead of buttons. */\n getHref?: (page: number) => string;\n /** @default 'md' */\n size?: PaginationSize;\n /** The landmark's name. @default 'Pagination' */\n 'aria-label'?: string;\n /** @default 'Previous page' */\n previousLabel?: string;\n /** @default 'Next page' */\n nextLabel?: string;\n /** Accessible name of a page control. @default (n) => `Page ${n}` */\n pageLabel?: (page: number) => string;\n ref?: Ref<HTMLElement>;\n}\n\n/**\n * Page controls in a `nav` landmark: previous, numbered pages with the\n * current one marked `aria-current=\"page\"`, and next. Distant pages\n * collapse into an ellipsis. Buttons by default; `getHref` renders links so\n * the pages are crawlable and open in new tabs. Built from Button and\n * IconButton, so it needs no keyboard model of its own.\n *\n * @status experimental\n * @category Navigation\n * @accessibility A `nav` landmark named by `aria-label`; the current page carries `aria-current=\"page\"`; previous and next are IconButtons with names; ellipses are hidden from assistive technology. With `getHref` the controls are links.\n * @do Use `getHref` when pages have URLs so they can be opened in new tabs and crawled.\n * Keep `siblings` at 1 on narrow screens.\n * @dont Disable the whole component while a page loads; disable only what cannot be pressed.\n */\nexport function Pagination({\n page,\n count,\n onPageChange,\n siblings = 1,\n boundaries = 1,\n getHref,\n size = 'md',\n 'aria-label': ariaLabel = 'Pagination',\n previousLabel = 'Previous page',\n nextLabel = 'Next page',\n pageLabel = (n) => `Page ${n}`,\n className,\n ref,\n ...rest\n}: PaginationProps) {\n const go = (target: number) => () => onPageChange?.(target);\n\n return (\n <nav {...rest} ref={ref} aria-label={ariaLabel} className={classes(styles.root, className)} data-size={size}>\n <ul className={styles.list}>\n <li>\n {page > 1 && getHref ? (\n <IconButton<HTMLAnchorElement> asChild label={previousLabel} icon={<ArrowLeft />} variant=\"ghost\" size={size} onClick={go(page - 1)}>\n <a href={getHref(page - 1)} />\n </IconButton>\n ) : (\n <IconButton label={previousLabel} icon={<ArrowLeft />} variant=\"ghost\" size={size} disabled={page <= 1} onClick={go(page - 1)} />\n )}\n </li>\n {paginationRange(page, count, siblings, boundaries).map((item) =>\n typeof item === 'number' ? (\n <li key={item}>\n {getHref ? (\n <Button<HTMLAnchorElement>\n asChild\n variant={item === page ? 'primary' : 'ghost'}\n size={size}\n className={styles.page}\n aria-label={pageLabel(item)}\n aria-current={item === page ? 'page' : undefined}\n onClick={go(item)}\n >\n <a href={getHref(item)}>{item}</a>\n </Button>\n ) : (\n <Button\n variant={item === page ? 'primary' : 'ghost'}\n size={size}\n className={styles.page}\n aria-label={pageLabel(item)}\n aria-current={item === page ? 'page' : undefined}\n onClick={go(item)}\n >\n {item}\n </Button>\n )}\n </li>\n ) : (\n <li key={item} className={styles.ellipsis} aria-hidden=\"true\">\n …\n </li>\n ),\n )}\n <li>\n {page < count && getHref ? (\n <IconButton<HTMLAnchorElement> asChild label={nextLabel} icon={<ArrowRight />} variant=\"ghost\" size={size} onClick={go(page + 1)}>\n <a href={getHref(page + 1)} />\n </IconButton>\n ) : (\n <IconButton label={nextLabel} icon={<ArrowRight />} variant=\"ghost\" size={size} disabled={page >= count} onClick={go(page + 1)} />\n )}\n </li>\n </ul>\n </nav>\n );\n}\n\nPagination.displayName = 'Pagination';\n"]}
@@ -1,4 +1,4 @@
1
- import { renderAsChild } from './chunk-ZVDN3GRI.js';
1
+ import { renderAsChild } from './chunk-QJG5ILK5.js';
2
2
  import { classes } from './chunk-MI4QUKQS.js';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
@@ -53,5 +53,5 @@ Card.Body = CardBody;
53
53
  Card.Footer = CardFooter;
54
54
 
55
55
  export { Card };
56
- //# sourceMappingURL=chunk-LA3YBXCR.js.map
57
- //# sourceMappingURL=chunk-LA3YBXCR.js.map
56
+ //# sourceMappingURL=chunk-HPQ462R5.js.map
57
+ //# sourceMappingURL=chunk-HPQ462R5.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/card/Card.module.css","../src/card/Card.tsx"],"names":["card","header","body","footer"],"mappings":";;;;;AAAA,IAAA,YAAA,GAAA;AAAA,EAKG,IAAA,EAAAA,WAAAA;AAAA,EAmDA,MAAA,EAAAC,aAAAA;AAAA,EACA,IAAA,EAAAC,WAAAA;AAAA,EACA,MAAA,EAAAC;AAAA,CAAA;ACLI,SAAS,IAAA,CAA0C;AAAA,EACxD,OAAA,GAAU,QAAA;AAAA,EACV,OAAA,GAAU,IAAA;AAAA,EACV,WAAA,GAAc,KAAA;AAAA,EACd,OAAA,GAAU,KAAA;AAAA,EACV,SAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAiB;AACf,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,GAAG,IAAA;AAAA,IACH,GAAA;AAAA,IACA,SAAA,EAAW,OAAA,CAAQ,YAAA,CAAO,IAAA,EAAM,SAAS,CAAA;AAAA,IACzC,cAAA,EAAgB,OAAA;AAAA,IAChB,cAAA,EAAgB,OAAA;AAAA,IAChB,kBAAA,EAAoB,cAAc,EAAA,GAAK,MAAA;AAAA;AAAA,IAEvC,QAAA,EAAU,QAAA,KAAa,WAAA,IAAe,CAAC,UAAU,CAAA,GAAI,MAAA;AAAA,GACvD;AAEA,EAAA,IAAI,OAAA,EAAS;AAGX,IAAA,OAAO,aAAA,CAAc,MAAA,EAAQ,QAAA,EAAU,KAAK,CAAA;AAAA,EAC9C;AAEA,EAAA,uBAAO,GAAA,CAAC,SAAA,EAAA,EAAS,GAAI,KAAA,EAAwC,QAAA,EAAS,CAAA;AACxE;AAEA,SAAS,WAAW,EAAE,SAAA,EAAW,GAAA,EAAK,GAAG,MAAK,EAAc;AAC1D,EAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,IAAA,EAAM,GAAA,EAAU,WAAW,OAAA,CAAQ,YAAA,CAAO,MAAA,EAAQ,SAAS,CAAA,EAAG,CAAA;AAChF;AAEA,SAAS,SAAS,EAAE,SAAA,EAAW,GAAA,EAAK,GAAG,MAAK,EAAc;AACxD,EAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,IAAA,EAAM,GAAA,EAAU,WAAW,OAAA,CAAQ,YAAA,CAAO,IAAA,EAAM,SAAS,CAAA,EAAG,CAAA;AAC9E;AAEA,SAAS,WAAW,EAAE,SAAA,EAAW,GAAA,EAAK,GAAG,MAAK,EAAc;AAC1D,EAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,IAAA,EAAM,GAAA,EAAU,WAAW,OAAA,CAAQ,YAAA,CAAO,MAAA,EAAQ,SAAS,CAAA,EAAG,CAAA;AAChF;AAEA,IAAA,CAAK,WAAA,GAAc,MAAA;AACnB,UAAA,CAAW,WAAA,GAAc,aAAA;AACzB,QAAA,CAAS,WAAA,GAAc,WAAA;AACvB,UAAA,CAAW,WAAA,GAAc,aAAA;AAEzB,IAAA,CAAK,MAAA,GAAS,UAAA;AACd,IAAA,CAAK,IAAA,GAAO,QAAA;AACZ,IAAA,CAAK,MAAA,GAAS,UAAA","file":"chunk-LA3YBXCR.js","sourcesContent":["/* Every value is a token (--card-*). Slots carry padding and dividers; the root is the surface. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .card {\n --_pad: var(--card-padding-md);\n\n display: flex;\n flex-direction: column;\n min-inline-size: 0;\n border: 1px solid transparent;\n border-radius: var(--card-radius);\n background-color: var(--card-bg);\n color: var(--card-fg);\n text-decoration: none;\n transition:\n border-color var(--card-motion-duration) var(--motion-easing-standard),\n box-shadow var(--card-motion-duration) var(--motion-easing-standard),\n translate var(--card-motion-duration) var(--motion-easing-standard);\n\n &[data-padding=\"sm\"] {\n --_pad: var(--card-padding-sm);\n }\n\n &[data-padding=\"lg\"] {\n --_pad: var(--card-padding-lg);\n }\n\n &[data-variant=\"raised\"] {\n box-shadow: var(--card-shadow);\n }\n\n &[data-variant=\"outlined\"] {\n border-color: var(--card-border);\n }\n\n &[data-variant=\"sunken\"] {\n background-color: var(--card-bg-sunken);\n }\n\n &[data-interactive] {\n cursor: pointer;\n\n &:hover {\n border-color: var(--card-border-hover);\n translate: 0 -1px;\n }\n\n &:focus-visible {\n outline: var(--card-focus-ring-width) solid var(--card-focus-ring);\n outline-offset: var(--card-focus-ring-offset);\n }\n }\n }\n\n .header,\n .body,\n .footer {\n padding: var(--_pad);\n }\n\n .header {\n display: flex;\n flex-direction: column;\n gap: var(--card-gap);\n border-block-end: 1px solid var(--card-divider);\n }\n\n .body {\n flex: 1;\n }\n\n .footer {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--card-gap);\n border-block-start: 1px solid var(--card-divider);\n }\n}\n","import type { HTMLAttributes, ReactNode, Ref } from 'react';\nimport { renderAsChild } from '../internal/asChild';\nimport { classes } from '../internal/classes';\nimport styles from './Card.module.css';\n\nexport type CardVariant = 'raised' | 'outlined' | 'sunken';\nexport type CardPadding = 'sm' | 'md' | 'lg';\n\nexport interface CardProps<E extends HTMLElement = HTMLElement> extends HTMLAttributes<HTMLElement> {\n /**\n * How the card separates from the page: `raised` by shadow, `outlined` by\n * border, `sunken` by a recessed surface.\n * @default 'raised'\n */\n variant?: CardVariant;\n /** One knob for every slot's inner spacing. @default 'md' */\n padding?: CardPadding;\n /**\n * Hover and focus affordances for a card that is itself a target. Pair it\n * with `asChild` and a link, or supply your own role and handlers.\n * @default false\n */\n interactive?: boolean;\n /**\n * Render the single child element as the card (an `<a>` for a link card),\n * merging the card's props into it.\n * @default false\n */\n asChild?: boolean;\n /** The rendered element; a `<section>` unless `asChild`. */\n ref?: Ref<E>;\n children: ReactNode;\n}\n\ninterface SlotProps extends HTMLAttributes<HTMLDivElement> {\n ref?: Ref<HTMLDivElement>;\n children?: ReactNode;\n}\n\n/**\n * A surface that groups related content. Compose with `Card.Header`,\n * `Card.Body` and `Card.Footer`; the slots carry the padding and dividers so\n * the root stays a plain surface. Every value comes from `--card-*` tokens;\n * state is exposed as `data-variant`, `data-padding` and `data-interactive`.\n *\n * @status stable\n * @category Layout\n * @accessibility A `section` by default (a `region` when it has an accessible name); with `asChild` the child element's own semantics apply. `interactive` adds a focus ring and a tab stop only when the element is not already focusable.\n * @do Give a card an `aria-label` or a heading in `Card.Header` when it is a landmark worth naming.\n * Use `asChild` with an `a` for a whole-card link.\n * @dont Put more than one primary action inside an interactive card.\n * Nest interactive cards.\n */\nexport function Card<E extends HTMLElement = HTMLElement>({\n variant = 'raised',\n padding = 'md',\n interactive = false,\n asChild = false,\n className,\n tabIndex,\n ref,\n children,\n ...rest\n}: CardProps<E>) {\n const props = {\n ...rest,\n ref,\n className: classes(styles.card, className),\n 'data-variant': variant,\n 'data-padding': padding,\n 'data-interactive': interactive ? '' : undefined,\n // An interactive section must be reachable; a link or button already is.\n tabIndex: tabIndex ?? (interactive && !asChild ? 0 : undefined),\n };\n\n if (asChild) {\n // The helper merges the forwarded ref with the child's; nothing reads it.\n // eslint-disable-next-line react-hooks/refs -- forwarded, not read\n return renderAsChild('Card', children, props);\n }\n\n return <section {...(props as HTMLAttributes<HTMLElement>)}>{children}</section>;\n}\n\nfunction CardHeader({ className, ref, ...rest }: SlotProps) {\n return <div {...rest} ref={ref} className={classes(styles.header, className)} />;\n}\n\nfunction CardBody({ className, ref, ...rest }: SlotProps) {\n return <div {...rest} ref={ref} className={classes(styles.body, className)} />;\n}\n\nfunction CardFooter({ className, ref, ...rest }: SlotProps) {\n return <div {...rest} ref={ref} className={classes(styles.footer, className)} />;\n}\n\nCard.displayName = 'Card';\nCardHeader.displayName = 'Card.Header';\nCardBody.displayName = 'Card.Body';\nCardFooter.displayName = 'Card.Footer';\n\nCard.Header = CardHeader;\nCard.Body = CardBody;\nCard.Footer = CardFooter;\n"]}
1
+ {"version":3,"sources":["../src/card/Card.module.css","../src/card/Card.tsx"],"names":["card","header","body","footer"],"mappings":";;;;;AAAA,IAAA,YAAA,GAAA;AAAA,EAKG,IAAA,EAAAA,WAAAA;AAAA,EAmDA,MAAA,EAAAC,aAAAA;AAAA,EACA,IAAA,EAAAC,WAAAA;AAAA,EACA,MAAA,EAAAC;AAAA,CAAA;ACLI,SAAS,IAAA,CAA0C;AAAA,EACxD,OAAA,GAAU,QAAA;AAAA,EACV,OAAA,GAAU,IAAA;AAAA,EACV,WAAA,GAAc,KAAA;AAAA,EACd,OAAA,GAAU,KAAA;AAAA,EACV,SAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAiB;AACf,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,GAAG,IAAA;AAAA,IACH,GAAA;AAAA,IACA,SAAA,EAAW,OAAA,CAAQ,YAAA,CAAO,IAAA,EAAM,SAAS,CAAA;AAAA,IACzC,cAAA,EAAgB,OAAA;AAAA,IAChB,cAAA,EAAgB,OAAA;AAAA,IAChB,kBAAA,EAAoB,cAAc,EAAA,GAAK,MAAA;AAAA;AAAA,IAEvC,QAAA,EAAU,QAAA,KAAa,WAAA,IAAe,CAAC,UAAU,CAAA,GAAI,MAAA;AAAA,GACvD;AAEA,EAAA,IAAI,OAAA,EAAS;AAGX,IAAA,OAAO,aAAA,CAAc,MAAA,EAAQ,QAAA,EAAU,KAAK,CAAA;AAAA,EAC9C;AAEA,EAAA,uBAAO,GAAA,CAAC,SAAA,EAAA,EAAS,GAAI,KAAA,EAAwC,QAAA,EAAS,CAAA;AACxE;AAEA,SAAS,WAAW,EAAE,SAAA,EAAW,GAAA,EAAK,GAAG,MAAK,EAAc;AAC1D,EAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,IAAA,EAAM,GAAA,EAAU,WAAW,OAAA,CAAQ,YAAA,CAAO,MAAA,EAAQ,SAAS,CAAA,EAAG,CAAA;AAChF;AAEA,SAAS,SAAS,EAAE,SAAA,EAAW,GAAA,EAAK,GAAG,MAAK,EAAc;AACxD,EAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,IAAA,EAAM,GAAA,EAAU,WAAW,OAAA,CAAQ,YAAA,CAAO,IAAA,EAAM,SAAS,CAAA,EAAG,CAAA;AAC9E;AAEA,SAAS,WAAW,EAAE,SAAA,EAAW,GAAA,EAAK,GAAG,MAAK,EAAc;AAC1D,EAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,IAAA,EAAM,GAAA,EAAU,WAAW,OAAA,CAAQ,YAAA,CAAO,MAAA,EAAQ,SAAS,CAAA,EAAG,CAAA;AAChF;AAEA,IAAA,CAAK,WAAA,GAAc,MAAA;AACnB,UAAA,CAAW,WAAA,GAAc,aAAA;AACzB,QAAA,CAAS,WAAA,GAAc,WAAA;AACvB,UAAA,CAAW,WAAA,GAAc,aAAA;AAEzB,IAAA,CAAK,MAAA,GAAS,UAAA;AACd,IAAA,CAAK,IAAA,GAAO,QAAA;AACZ,IAAA,CAAK,MAAA,GAAS,UAAA","file":"chunk-HPQ462R5.js","sourcesContent":["/* Every value is a token (--card-*). Slots carry padding and dividers; the root is the surface. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .card {\n --_pad: var(--card-padding-md);\n\n display: flex;\n flex-direction: column;\n min-inline-size: 0;\n border: 1px solid transparent;\n border-radius: var(--card-radius);\n background-color: var(--card-bg);\n color: var(--card-fg);\n text-decoration: none;\n transition:\n border-color var(--card-motion-duration) var(--motion-easing-standard),\n box-shadow var(--card-motion-duration) var(--motion-easing-standard),\n translate var(--card-motion-duration) var(--motion-easing-standard);\n\n &[data-padding=\"sm\"] {\n --_pad: var(--card-padding-sm);\n }\n\n &[data-padding=\"lg\"] {\n --_pad: var(--card-padding-lg);\n }\n\n &[data-variant=\"raised\"] {\n box-shadow: var(--card-shadow);\n }\n\n &[data-variant=\"outlined\"] {\n border-color: var(--card-border);\n }\n\n &[data-variant=\"sunken\"] {\n background-color: var(--card-bg-sunken);\n }\n\n &[data-interactive] {\n cursor: pointer;\n\n &:hover {\n border-color: var(--card-border-hover);\n translate: 0 -1px;\n }\n\n &:focus-visible {\n outline: var(--card-focus-ring-width) solid var(--card-focus-ring);\n outline-offset: var(--card-focus-ring-offset);\n }\n }\n }\n\n .header,\n .body,\n .footer {\n padding: var(--_pad);\n }\n\n .header {\n display: flex;\n flex-direction: column;\n gap: var(--card-gap);\n border-block-end: 1px solid var(--card-divider);\n }\n\n .body {\n flex: 1;\n }\n\n .footer {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--card-gap);\n border-block-start: 1px solid var(--card-divider);\n }\n}\n","import type { HTMLAttributes, ReactNode, Ref } from 'react';\nimport { renderAsChild } from '../internal/asChild';\nimport { classes } from '../internal/classes';\nimport styles from './Card.module.css';\n\nexport type CardVariant = 'raised' | 'outlined' | 'sunken';\nexport type CardPadding = 'sm' | 'md' | 'lg';\n\nexport interface CardProps<E extends HTMLElement = HTMLElement> extends HTMLAttributes<HTMLElement> {\n /**\n * How the card separates from the page: `raised` by shadow, `outlined` by\n * border, `sunken` by a recessed surface.\n * @default 'raised'\n */\n variant?: CardVariant;\n /** One knob for every slot's inner spacing. @default 'md' */\n padding?: CardPadding;\n /**\n * Hover and focus affordances for a card that is itself a target. Pair it\n * with `asChild` and a link, or supply your own role and handlers.\n * @default false\n */\n interactive?: boolean;\n /**\n * Render the single child element as the card (an `<a>` for a link card),\n * merging the card's props into it.\n * @default false\n */\n asChild?: boolean;\n /** The rendered element; a `<section>` unless `asChild`. */\n ref?: Ref<E>;\n children: ReactNode;\n}\n\ninterface SlotProps extends HTMLAttributes<HTMLDivElement> {\n ref?: Ref<HTMLDivElement>;\n children?: ReactNode;\n}\n\n/**\n * A surface that groups related content. Compose with `Card.Header`,\n * `Card.Body` and `Card.Footer`; the slots carry the padding and dividers so\n * the root stays a plain surface. Every value comes from `--card-*` tokens;\n * state is exposed as `data-variant`, `data-padding` and `data-interactive`.\n *\n * @status stable\n * @category Layout\n * @accessibility A `section` by default (a `region` when it has an accessible name); with `asChild` the child element's own semantics apply. `interactive` adds a focus ring and a tab stop only when the element is not already focusable.\n * @do Give a card an `aria-label` or a heading in `Card.Header` when it is a landmark worth naming.\n * Use `asChild` with an `a` for a whole-card link.\n * @dont Put more than one primary action inside an interactive card.\n * Nest interactive cards.\n */\nexport function Card<E extends HTMLElement = HTMLElement>({\n variant = 'raised',\n padding = 'md',\n interactive = false,\n asChild = false,\n className,\n tabIndex,\n ref,\n children,\n ...rest\n}: CardProps<E>) {\n const props = {\n ...rest,\n ref,\n className: classes(styles.card, className),\n 'data-variant': variant,\n 'data-padding': padding,\n 'data-interactive': interactive ? '' : undefined,\n // An interactive section must be reachable; a link or button already is.\n tabIndex: tabIndex ?? (interactive && !asChild ? 0 : undefined),\n };\n\n if (asChild) {\n // The helper merges the forwarded ref with the child's; nothing reads it.\n // eslint-disable-next-line react-hooks/refs -- forwarded, not read\n return renderAsChild('Card', children, props);\n }\n\n return <section {...(props as HTMLAttributes<HTMLElement>)}>{children}</section>;\n}\n\nfunction CardHeader({ className, ref, ...rest }: SlotProps) {\n return <div {...rest} ref={ref} className={classes(styles.header, className)} />;\n}\n\nfunction CardBody({ className, ref, ...rest }: SlotProps) {\n return <div {...rest} ref={ref} className={classes(styles.body, className)} />;\n}\n\nfunction CardFooter({ className, ref, ...rest }: SlotProps) {\n return <div {...rest} ref={ref} className={classes(styles.footer, className)} />;\n}\n\nCard.displayName = 'Card';\nCardHeader.displayName = 'Card.Header';\nCardBody.displayName = 'Card.Body';\nCardFooter.displayName = 'Card.Footer';\n\nCard.Header = CardHeader;\nCard.Body = CardBody;\nCard.Footer = CardFooter;\n"]}
@@ -0,0 +1,28 @@
1
+ import { VisuallyHidden } from './chunk-IB5UUE3S.js';
2
+ import { Icon } from './chunk-O5LII5XP.js';
3
+ import { classes } from './chunk-MI4QUKQS.js';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ // src/badge/Badge.module.css
7
+ var Badge_default = {
8
+ badge: "Badge_badge"
9
+ };
10
+ var DEV = typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
11
+ function Badge({ tone = "neutral", variant = "subtle", size = "md", icon, count, max = 99, label, className, ref, children, ...rest }) {
12
+ if (count !== void 0 && count <= 0) return null;
13
+ const dot = variant === "dot";
14
+ if (DEV && dot && !label) {
15
+ console.warn('Badge: variant="dot" has no visible text, so it needs a `label` for assistive technology.');
16
+ }
17
+ const text = count === void 0 ? children : count > max ? `${max}+` : String(count);
18
+ return /* @__PURE__ */ jsxs("span", { ...rest, ref, className: classes(Badge_default.badge, className), "data-tone": tone, "data-variant": variant, "data-size": size, children: [
19
+ !dot && icon && /* @__PURE__ */ jsx(Icon, { size: "inherit", children: icon }),
20
+ !dot && text,
21
+ label && (dot || count !== void 0) && /* @__PURE__ */ jsx(VisuallyHidden, { children: dot ? label : ` ${label}` })
22
+ ] });
23
+ }
24
+ Badge.displayName = "Badge";
25
+
26
+ export { Badge };
27
+ //# sourceMappingURL=chunk-KSLKNWWM.js.map
28
+ //# sourceMappingURL=chunk-KSLKNWWM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/badge/Badge.module.css","../src/badge/Badge.tsx"],"names":["badge"],"mappings":";;;;;;AAAA,IAAA,aAAA,GAAA;AAAA,EAKG,KAAA,EAAAA;AAAA,CAAA;ACmCH,IAAM,MAAM,OAAO,OAAA,KAAY,WAAA,IAAe,OAAA,CAAQ,KAAK,QAAA,KAAa,YAAA;AAiBjE,SAAS,MAAM,EAAE,IAAA,GAAO,WAAW,OAAA,GAAU,QAAA,EAAU,OAAO,IAAA,EAAM,IAAA,EAAM,KAAA,EAAO,GAAA,GAAM,IAAI,KAAA,EAAO,SAAA,EAAW,KAAK,QAAA,EAAU,GAAG,MAAK,EAAe;AACxJ,EAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,IAAS,CAAA,EAAG,OAAO,IAAA;AAE9C,EAAA,MAAM,MAAM,OAAA,KAAY,KAAA;AACxB,EAAA,IAAI,GAAA,IAAO,GAAA,IAAO,CAAC,KAAA,EAAO;AACxB,IAAA,OAAA,CAAQ,KAAK,2FAA2F,CAAA;AAAA,EAC1G;AACA,EAAA,MAAM,IAAA,GAAO,KAAA,KAAU,MAAA,GAAY,QAAA,GAAW,KAAA,GAAQ,MAAM,CAAA,EAAG,GAAG,CAAA,CAAA,CAAA,GAAM,MAAA,CAAO,KAAK,CAAA;AAEpF,EAAA,4BACG,MAAA,EAAA,EAAM,GAAG,IAAA,EAAM,GAAA,EAAU,WAAW,OAAA,CAAQ,aAAA,CAAO,KAAA,EAAO,SAAS,GAAG,WAAA,EAAW,IAAA,EAAM,cAAA,EAAc,OAAA,EAAS,aAAW,IAAA,EACvH,QAAA,EAAA;AAAA,IAAA,CAAC,OAAO,IAAA,oBAAQ,GAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAK,WAAW,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,IAC3C,CAAC,GAAA,IAAO,IAAA;AAAA,IACR,KAAA,KAAU,GAAA,IAAO,KAAA,KAAU,MAAA,CAAA,oBAAc,GAAA,CAAC,kBAAgB,QAAA,EAAA,GAAA,GAAM,KAAA,GAAQ,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAG;AAAA,GAAA,EACvF,CAAA;AAEJ;AAEA,KAAA,CAAM,WAAA,GAAc,OAAA","file":"chunk-KSLKNWWM.js","sourcesContent":["/* Every value is a token (--badge-*). Tone × variant resolve into private custom properties. */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .badge {\n --_bg: var(--badge-neutral-subtle-bg);\n --_fg: var(--badge-neutral-subtle-fg);\n\n display: inline-flex;\n align-items: center;\n gap: var(--badge-gap);\n padding-block: var(--badge-padding-block);\n padding-inline: var(--badge-padding-inline-md);\n border-radius: var(--badge-radius);\n background-color: var(--_bg);\n color: var(--_fg);\n font-size: var(--badge-font-size-md);\n font-weight: var(--badge-font-weight);\n line-height: var(--badge-line-height);\n white-space: nowrap;\n\n &[data-size=\"sm\"] {\n padding-inline: var(--badge-padding-inline-sm);\n font-size: var(--badge-font-size-sm);\n }\n\n &[data-tone=\"neutral\"][data-variant=\"solid\"] {\n --_bg: var(--badge-neutral-solid-bg);\n --_fg: var(--badge-neutral-solid-fg);\n }\n\n &[data-tone=\"neutral\"][data-variant=\"subtle\"] {\n --_bg: var(--badge-neutral-subtle-bg);\n --_fg: var(--badge-neutral-subtle-fg);\n }\n\n &[data-tone=\"info\"][data-variant=\"solid\"] {\n --_bg: var(--badge-info-solid-bg);\n --_fg: var(--badge-info-solid-fg);\n }\n\n &[data-tone=\"info\"][data-variant=\"subtle\"] {\n --_bg: var(--badge-info-subtle-bg);\n --_fg: var(--badge-info-subtle-fg);\n }\n\n &[data-tone=\"success\"][data-variant=\"solid\"] {\n --_bg: var(--badge-success-solid-bg);\n --_fg: var(--badge-success-solid-fg);\n }\n\n &[data-tone=\"success\"][data-variant=\"subtle\"] {\n --_bg: var(--badge-success-subtle-bg);\n --_fg: var(--badge-success-subtle-fg);\n }\n\n &[data-tone=\"warning\"][data-variant=\"solid\"] {\n --_bg: var(--badge-warning-solid-bg);\n --_fg: var(--badge-warning-solid-fg);\n }\n\n &[data-tone=\"warning\"][data-variant=\"subtle\"] {\n --_bg: var(--badge-warning-subtle-bg);\n --_fg: var(--badge-warning-subtle-fg);\n }\n\n &[data-tone=\"error\"][data-variant=\"solid\"] {\n --_bg: var(--badge-error-solid-bg);\n --_fg: var(--badge-error-solid-fg);\n }\n\n &[data-tone=\"error\"][data-variant=\"subtle\"] {\n --_bg: var(--badge-error-subtle-bg);\n --_fg: var(--badge-error-subtle-fg);\n }\n }\n\n /* A presence mark: the tone's solid fill, no text, no padding. After the tone rules so --_bg is set. */\n .badge[data-variant=\"dot\"] {\n inline-size: var(--badge-dot-size);\n block-size: var(--badge-dot-size);\n padding: 0;\n vertical-align: middle;\n }\n\n .badge[data-tone=\"neutral\"][data-variant=\"dot\"] {\n --_bg: var(--badge-neutral-solid-bg);\n }\n\n .badge[data-tone=\"info\"][data-variant=\"dot\"] {\n --_bg: var(--badge-info-solid-bg);\n }\n\n .badge[data-tone=\"success\"][data-variant=\"dot\"] {\n --_bg: var(--badge-success-solid-bg);\n }\n\n .badge[data-tone=\"warning\"][data-variant=\"dot\"] {\n --_bg: var(--badge-warning-solid-bg);\n }\n\n .badge[data-tone=\"error\"][data-variant=\"dot\"] {\n --_bg: var(--badge-error-solid-bg);\n }\n}\n","import type { HTMLAttributes, ReactNode, Ref } from 'react';\nimport { Icon } from '../icon';\nimport { classes } from '../internal/classes';\nimport { VisuallyHidden } from '../visually-hidden';\nimport styles from './Badge.module.css';\n\nexport type BadgeTone = 'neutral' | 'info' | 'success' | 'warning' | 'error';\nexport type BadgeVariant = 'solid' | 'subtle' | 'dot';\nexport type BadgeSize = 'sm' | 'md';\n\nexport interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n /** Meaning, not colour: `neutral` for counts and tags. @default 'neutral' */\n tone?: BadgeTone;\n /**\n * `solid` fills with the tone; `subtle` tints and uses the tone as text; `dot` is a\n * small filled circle with no visible text, which needs a `label`. @default 'subtle'\n */\n variant?: BadgeVariant;\n /** @default 'md' */\n size?: BadgeSize;\n /** Leading glyph, decorative. */\n icon?: ReactNode;\n /**\n * A number to show instead of children, clamped to `max` (\"99+\"). Zero or less\n * renders nothing: an empty inbox has no badge.\n */\n count?: number;\n /** The highest count shown as is. @default 99 */\n max?: number;\n /**\n * What the badge means, for assistive technology. Required for `variant=\"dot\"`\n * (\"Unread messages\"), where it is the only content. With a `count` it is read\n * after the number: `count={3} label=\"unread\"` is announced as \"3 unread\".\n */\n label?: string;\n ref?: Ref<HTMLSpanElement>;\n children?: ReactNode;\n}\n\n// Guarded: a consumer's bundler may not define `process`.\nconst DEV = typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production';\n\n/**\n * A small label for status, counts and tags. Tone and variant resolve\n * through `--badge-*` onto the status tokens, whose contrast is proven by\n * the token tests. Not interactive: for a removable chip, compose with a\n * Button.\n *\n * @status stable\n * @category Feedback\n * @accessibility Plain text: no role, no interaction, and deliberately no live region: a badge that is there when the page renders must not be announced as news (put `role=\"status\"` on a wrapper yourself if a count changes while the user is on the page). A `dot` has no visible text, so its `label` is rendered visually hidden; a `count` above `max` reads as \"99+\", followed by the `label` if there is one. Every tone × variant pair meets WCAG AA, proven by the token tests. Tone is reinforced by the text, not only by colour.\n * @do Keep the text to one or two words.\n * @do Give a `dot` a `label` that says what it marks, and a `count` a `label` that says what is counted.\n * Pair a leading icon with text, never alone.\n * @dont Make it clickable; compose a Button for a removable chip.\n * Use tone alone to convey meaning; say it in the text.\n */\nexport function Badge({ tone = 'neutral', variant = 'subtle', size = 'md', icon, count, max = 99, label, className, ref, children, ...rest }: BadgeProps) {\n if (count !== undefined && count <= 0) return null;\n\n const dot = variant === 'dot';\n if (DEV && dot && !label) {\n console.warn('Badge: variant=\"dot\" has no visible text, so it needs a `label` for assistive technology.');\n }\n const text = count === undefined ? children : count > max ? `${max}+` : String(count);\n\n return (\n <span {...rest} ref={ref} className={classes(styles.badge, className)} data-tone={tone} data-variant={variant} data-size={size}>\n {!dot && icon && <Icon size=\"inherit\">{icon}</Icon>}\n {!dot && text}\n {label && (dot || count !== undefined) && <VisuallyHidden>{dot ? label : ` ${label}`}</VisuallyHidden>}\n </span>\n );\n}\n\nBadge.displayName = 'Badge';\n"]}
@@ -0,0 +1,85 @@
1
+ import { classes } from './chunk-MI4QUKQS.js';
2
+ import { useId, useState } from 'react';
3
+ import { Close } from '@pearpages/pulp-icons';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ // src/chip/Chip.module.css
7
+ var Chip_default = {
8
+ root: "Chip_root",
9
+ label: "Chip_label",
10
+ remove: "Chip_remove"
11
+ };
12
+ function Chip({
13
+ selected,
14
+ defaultSelected,
15
+ onSelectedChange,
16
+ onRemove,
17
+ removeLabel = "Remove",
18
+ size = "md",
19
+ tone = "neutral",
20
+ disabled,
21
+ className,
22
+ onClick,
23
+ ref,
24
+ children,
25
+ ...rest
26
+ }) {
27
+ const id = useId();
28
+ const [own, setOwn] = useState(defaultSelected ?? false);
29
+ const toggles = selected !== void 0 || defaultSelected !== void 0 || onSelectedChange !== void 0;
30
+ const pressed = selected ?? own;
31
+ const interactive = toggles || onClick !== void 0;
32
+ const label = interactive ? /* @__PURE__ */ jsx(
33
+ "button",
34
+ {
35
+ type: "button",
36
+ ...rest,
37
+ ref,
38
+ id: `${id}-label`,
39
+ className: Chip_default.label,
40
+ disabled,
41
+ "aria-pressed": toggles ? pressed : void 0,
42
+ onClick: (event) => {
43
+ onClick?.(event);
44
+ if (event.defaultPrevented || !toggles) return;
45
+ if (selected === void 0) setOwn(!pressed);
46
+ onSelectedChange?.(!pressed);
47
+ },
48
+ children
49
+ }
50
+ ) : /* @__PURE__ */ jsx("span", { id: `${id}-label`, className: Chip_default.label, ref, children });
51
+ return /* @__PURE__ */ jsxs(
52
+ "span",
53
+ {
54
+ className: classes(Chip_default.root, className),
55
+ "data-size": size,
56
+ "data-tone": tone,
57
+ "data-selected": toggles && pressed ? "" : void 0,
58
+ "data-interactive": interactive ? "" : void 0,
59
+ "data-disabled": disabled ? "" : void 0,
60
+ role: interactive && onRemove ? "group" : void 0,
61
+ "aria-labelledby": interactive && onRemove ? `${id}-label` : void 0,
62
+ children: [
63
+ label,
64
+ onRemove && /* @__PURE__ */ jsx(
65
+ "button",
66
+ {
67
+ type: "button",
68
+ id: `${id}-remove`,
69
+ className: Chip_default.remove,
70
+ disabled,
71
+ "aria-label": removeLabel,
72
+ "aria-labelledby": `${id}-remove ${id}-label`,
73
+ onClick: onRemove,
74
+ children: /* @__PURE__ */ jsx(Close, { "aria-hidden": "true" })
75
+ }
76
+ )
77
+ ]
78
+ }
79
+ );
80
+ }
81
+ Chip.displayName = "Chip";
82
+
83
+ export { Chip };
84
+ //# sourceMappingURL=chunk-OKA2PLDV.js.map
85
+ //# sourceMappingURL=chunk-OKA2PLDV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/chip/Chip.module.css","../src/chip/Chip.tsx"],"names":["root","label","remove"],"mappings":"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","file":"chunk-OKA2PLDV.js","sourcesContent":["/* Every value is a token: --chip-* in packages/tokens/tokens/component/chip.json */\n\n@layer reset, tokens, vendor, base, components, utilities;\n\n@layer components {\n .root {\n --_bg: var(--chip-neutral-bg);\n --_bg-hover: var(--chip-neutral-bg-hover);\n --_fg: var(--chip-neutral-fg);\n --_border: var(--chip-neutral-border);\n --_selected-bg: var(--chip-neutral-selected-bg);\n --_selected-fg: var(--chip-neutral-selected-fg);\n --_height: var(--chip-height-md);\n --_padding: var(--chip-padding-x-md);\n\n display: inline-flex;\n align-items: stretch;\n box-sizing: border-box;\n min-block-size: var(--_height);\n max-inline-size: 100%;\n border: var(--chip-border-width) solid var(--_border);\n border-radius: var(--chip-radius);\n background: var(--_bg);\n color: var(--_fg);\n font-family: var(--font-family-body);\n font-size: var(--chip-font-size-md);\n font-weight: var(--chip-weight);\n line-height: 1;\n white-space: nowrap;\n vertical-align: middle;\n\n &[data-tone='action'] {\n --_bg: var(--chip-action-bg);\n --_bg-hover: var(--chip-action-bg-hover);\n --_fg: var(--chip-action-fg);\n --_border: var(--chip-action-border);\n --_selected-bg: var(--chip-action-selected-bg);\n --_selected-fg: var(--chip-action-selected-fg);\n }\n\n &[data-size='sm'] {\n --_height: var(--chip-height-sm);\n --_padding: var(--chip-padding-x-sm);\n\n font-size: var(--chip-font-size-sm);\n }\n\n &[data-size='lg'] {\n --_height: var(--chip-height-lg);\n --_padding: var(--chip-padding-x-lg);\n\n font-size: var(--chip-font-size-lg);\n }\n\n &[data-selected] {\n border-color: var(--_selected-bg);\n background: var(--_selected-bg);\n color: var(--_selected-fg);\n }\n\n &[data-disabled] {\n opacity: 0.55;\n }\n }\n\n /* The two controls are transparent: the pill is painted once, on the root. */\n .label,\n .remove {\n display: inline-flex;\n align-items: center;\n border: 0;\n border-radius: var(--chip-radius);\n background: transparent;\n color: inherit;\n font: inherit;\n\n &:is(button) {\n cursor: pointer;\n }\n\n &:is(button):disabled {\n cursor: not-allowed;\n }\n\n &:focus-visible {\n outline: var(--chip-focus-ring-width) solid var(--chip-focus-ring);\n outline-offset: var(--chip-focus-ring-offset);\n }\n }\n\n .label {\n min-inline-size: 0;\n padding-block: 0;\n padding-inline: var(--_padding);\n overflow: hidden;\n text-overflow: ellipsis;\n\n /* With a remove button the label gives up its end padding to it. */\n &:not(:last-child) {\n padding-inline-end: var(--chip-gap);\n }\n }\n\n /* On the label, not `.root:has(.label:hover)`: Firefox 120, the support floor, has no :has(). */\n .root:not([data-selected], [data-disabled]) button.label:hover {\n background: var(--_bg-hover);\n }\n\n .remove {\n flex: none;\n justify-content: center;\n\n /* A square as tall as the chip, so the target is never smaller than the chip itself. */\n inline-size: var(--_height);\n padding: 0;\n }\n}\n","import { useId, useState, type ButtonHTMLAttributes, type ReactNode, type Ref } from 'react';\nimport { Close } from '@pearpages/pulp-icons';\nimport { classes } from '../internal/classes';\nimport styles from './Chip.module.css';\n\nexport type ChipSize = 'sm' | 'md' | 'lg';\nexport type ChipTone = 'neutral' | 'action';\n\nexport interface ChipProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'value'> {\n /** Controlled pressed state. Passing it (or `defaultSelected`, or `onSelectedChange`) makes the chip a toggle. */\n selected?: boolean;\n /** Uncontrolled initial pressed state. */\n defaultSelected?: boolean;\n /** Called with the next state when the chip is pressed. */\n onSelectedChange?: (selected: boolean) => void;\n /** Adds a remove button after the label: a second button beside the chip, never inside it. */\n onRemove?: () => void;\n /** The remove button is named \"`removeLabel` + the chip's label\" (\"Remove Vegan\"). @default 'Remove' */\n removeLabel?: string;\n /** `sm` is 24px high, the minimum target size. @default 'md' */\n size?: ChipSize;\n /** `action` takes the brand's colour; a selected chip is filled in either tone. @default 'neutral' */\n tone?: ChipTone;\n\n /** The `button` that carries the label, or the `span` when the chip neither toggles nor has an `onClick`. */\n ref?: Ref<HTMLButtonElement>;\n children: ReactNode;\n}\n\n/**\n * A small pill for a choice or a value the user controls: a filter that\n * toggles (`selected`), a tag that can be removed (`onRemove`), or both. The\n * label is a button only when pressing it does something.\n *\n * @status experimental\n * @category Actions\n * @accessibility A toggle chip is a native `button` with `aria-pressed`, so Space and Enter work and the state is announced. The remove control is a second `button`, a sibling of the first (a button inside a button is invalid HTML and unreachable by keyboard), named by `removeLabel` plus the chip's own label through `aria-labelledby`: \"Remove Vegan\", not \"Remove\" six times. The pair is wrapped in a `role=\"group\"` named by the label only when there are two controls. `disabled` disables both. After removing a chip, move focus yourself (to the next chip or the input): the button that had it is gone.\n * @do Use a group of toggle chips for filters where several can be on at once.\n * @do Keep the label to a word or two; a chip does not wrap.\n * @dont Use a chip that does nothing as a label or a status: that is a Badge.\n * @dont Use chips for one choice out of several; that is a SegmentedControl or a RadioGroup.\n */\nexport function Chip({\n selected,\n defaultSelected,\n onSelectedChange,\n onRemove,\n removeLabel = 'Remove',\n size = 'md',\n tone = 'neutral',\n disabled,\n className,\n onClick,\n ref,\n children,\n ...rest\n}: ChipProps) {\n const id = useId();\n const [own, setOwn] = useState(defaultSelected ?? false);\n const toggles = selected !== undefined || defaultSelected !== undefined || onSelectedChange !== undefined;\n const pressed = selected ?? own;\n const interactive = toggles || onClick !== undefined;\n\n const label = interactive ? (\n <button\n type=\"button\"\n {...rest}\n ref={ref}\n id={`${id}-label`}\n className={styles.label}\n disabled={disabled}\n aria-pressed={toggles ? pressed : undefined}\n onClick={(event) => {\n onClick?.(event);\n if (event.defaultPrevented || !toggles) return;\n if (selected === undefined) setOwn(!pressed);\n onSelectedChange?.(!pressed);\n }}\n >\n {children}\n </button>\n ) : (\n <span id={`${id}-label`} className={styles.label} ref={ref as Ref<HTMLSpanElement>}>\n {children}\n </span>\n );\n\n return (\n <span\n className={classes(styles.root, className)}\n data-size={size}\n data-tone={tone}\n data-selected={toggles && pressed ? '' : undefined}\n data-interactive={interactive ? '' : undefined}\n data-disabled={disabled ? '' : undefined}\n role={interactive && onRemove ? 'group' : undefined}\n aria-labelledby={interactive && onRemove ? `${id}-label` : undefined}\n >\n {label}\n {onRemove && (\n <button\n type=\"button\"\n id={`${id}-remove`}\n className={styles.remove}\n disabled={disabled}\n aria-label={removeLabel}\n aria-labelledby={`${id}-remove ${id}-label`}\n onClick={onRemove}\n >\n <Close aria-hidden=\"true\" />\n </button>\n )}\n </span>\n );\n}\n\nChip.displayName = 'Chip';\n"]}
@@ -1,4 +1,4 @@
1
- import { Field } from './chunk-M5VL22MY.js';
1
+ import { Field } from './chunk-SXMORGSG.js';
2
2
  import { classes } from './chunk-MI4QUKQS.js';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
 
@@ -39,5 +39,5 @@ function ToggleField({
39
39
  }
40
40
 
41
41
  export { ToggleField };
42
- //# sourceMappingURL=chunk-6BIEW4WJ.js.map
43
- //# sourceMappingURL=chunk-6BIEW4WJ.js.map
42
+ //# sourceMappingURL=chunk-Q6SYKNZ5.js.map
43
+ //# sourceMappingURL=chunk-Q6SYKNZ5.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/ToggleField.tsx"],"names":[],"mappings":";;;;AA0BO,SAAS,WAAA,CAAY;AAAA,EAC1B,KAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,EAAA;AAAA,EACA,SAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,kBAAA,EAAoB;AACtB,CAAA,EAAqB;AACnB,EAAA,MAAM,UAAU,KAAA,KAAU,MAAA,IAAa,UAAU,IAAA,IAAQ,KAAA,KAAU,SAAS,KAAA,KAAU,EAAA;AACtF,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,EAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA,EAAU,QAAQ,QAAQ,CAAA;AAAA,MAC1B,QAAA,EAAU,QAAQ,QAAQ,CAAA;AAAA,MAC1B,SAAA,EAAW,OAAA,CAAQ,aAAA,EAAe,SAAS,CAAA;AAAA,MAC3C,WAAA,EAAW,IAAA;AAAA,MAEX,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAW,YAAA,EACd,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,CAAM,OAAA,EAAN,EAAc,kBAAA,EAAkB,aAAc,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,0BACvD,GAAA,CAAC,KAAA,CAAM,KAAA,EAAN,EAAa,QAAA,EAAA,KAAA,EAAM;AAAA,SAAA,EACtB,CAAA;AAAA,QACC,WAAA,oBAAe,GAAA,CAAC,KAAA,CAAM,WAAA,EAAN,EAAmB,QAAA,EAAA,WAAA,EAAY,CAAA;AAAA,QAC/C,OAAA,oBAAW,GAAA,CAAC,KAAA,CAAM,KAAA,EAAN,EAAa,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA;AAAA,GAClC;AAEJ","file":"chunk-6BIEW4WJ.js","sourcesContent":["import type { ReactNode } from 'react';\nimport { Field } from '../field';\nimport { classes } from './classes';\n\nexport type ToggleSize = 'sm' | 'md' | 'lg';\n\nexport interface ToggleFieldProps {\n /** Visible inline label. */\n label: ReactNode;\n description?: ReactNode;\n error?: ReactNode;\n size: ToggleSize;\n disabled?: boolean;\n required?: boolean;\n id?: string;\n className?: string;\n /** The Field root class of the concrete control (checkbox, switch). */\n rootClassName: string | undefined;\n /** The class of the row holding the control and its label. */\n rowClassName: string | undefined;\n /** The single `<input>` element; Field.Control wires it. */\n control: ReactNode;\n 'aria-describedby'?: string;\n}\n\n/** Field wiring for a control whose label sits beside it: Checkbox, Switch. */\nexport function ToggleField({\n label,\n description,\n error,\n size,\n disabled,\n required,\n id,\n className,\n rootClassName,\n rowClassName,\n control,\n 'aria-describedby': describedBy,\n}: ToggleFieldProps) {\n const invalid = error !== undefined && error !== null && error !== false && error !== '';\n return (\n <Field\n id={id}\n invalid={invalid}\n disabled={Boolean(disabled)}\n required={Boolean(required)}\n className={classes(rootClassName, className)}\n data-size={size}\n >\n <div className={rowClassName}>\n <Field.Control aria-describedby={describedBy}>{control}</Field.Control>\n <Field.Label>{label}</Field.Label>\n </div>\n {description && <Field.Description>{description}</Field.Description>}\n {invalid && <Field.Error>{error}</Field.Error>}\n </Field>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/ToggleField.tsx"],"names":[],"mappings":";;;;AA0BO,SAAS,WAAA,CAAY;AAAA,EAC1B,KAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,EAAA;AAAA,EACA,SAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,kBAAA,EAAoB;AACtB,CAAA,EAAqB;AACnB,EAAA,MAAM,UAAU,KAAA,KAAU,MAAA,IAAa,UAAU,IAAA,IAAQ,KAAA,KAAU,SAAS,KAAA,KAAU,EAAA;AACtF,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,EAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA,EAAU,QAAQ,QAAQ,CAAA;AAAA,MAC1B,QAAA,EAAU,QAAQ,QAAQ,CAAA;AAAA,MAC1B,SAAA,EAAW,OAAA,CAAQ,aAAA,EAAe,SAAS,CAAA;AAAA,MAC3C,WAAA,EAAW,IAAA;AAAA,MAEX,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAW,YAAA,EACd,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,CAAM,OAAA,EAAN,EAAc,kBAAA,EAAkB,aAAc,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,0BACvD,GAAA,CAAC,KAAA,CAAM,KAAA,EAAN,EAAa,QAAA,EAAA,KAAA,EAAM;AAAA,SAAA,EACtB,CAAA;AAAA,QACC,WAAA,oBAAe,GAAA,CAAC,KAAA,CAAM,WAAA,EAAN,EAAmB,QAAA,EAAA,WAAA,EAAY,CAAA;AAAA,QAC/C,OAAA,oBAAW,GAAA,CAAC,KAAA,CAAM,KAAA,EAAN,EAAa,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA;AAAA,GAClC;AAEJ","file":"chunk-Q6SYKNZ5.js","sourcesContent":["import type { ReactNode } from 'react';\nimport { Field } from '../field';\nimport { classes } from './classes';\n\nexport type ToggleSize = 'sm' | 'md' | 'lg';\n\nexport interface ToggleFieldProps {\n /** Visible inline label. */\n label: ReactNode;\n description?: ReactNode;\n error?: ReactNode;\n size: ToggleSize;\n disabled?: boolean;\n required?: boolean;\n id?: string;\n className?: string;\n /** The Field root class of the concrete control (checkbox, switch). */\n rootClassName: string | undefined;\n /** The class of the row holding the control and its label. */\n rowClassName: string | undefined;\n /** The single `<input>` element; Field.Control wires it. */\n control: ReactNode;\n 'aria-describedby'?: string;\n}\n\n/** Field wiring for a control whose label sits beside it: Checkbox, Switch. */\nexport function ToggleField({\n label,\n description,\n error,\n size,\n disabled,\n required,\n id,\n className,\n rootClassName,\n rowClassName,\n control,\n 'aria-describedby': describedBy,\n}: ToggleFieldProps) {\n const invalid = error !== undefined && error !== null && error !== false && error !== '';\n return (\n <Field\n id={id}\n invalid={invalid}\n disabled={Boolean(disabled)}\n required={Boolean(required)}\n className={classes(rootClassName, className)}\n data-size={size}\n >\n <div className={rowClassName}>\n <Field.Control aria-describedby={describedBy}>{control}</Field.Control>\n <Field.Label>{label}</Field.Label>\n </div>\n {description && <Field.Description>{description}</Field.Description>}\n {invalid && <Field.Error>{error}</Field.Error>}\n </Field>\n );\n}\n"]}