@porsche-design-system/components-react 4.3.0 → 4.4.0-rc.1

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 (38) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/cjs/lib/components/popover.wrapper.cjs +4 -3
  3. package/esm/lib/components/popover.wrapper.d.ts +26 -2
  4. package/esm/lib/components/popover.wrapper.mjs +5 -4
  5. package/package.json +2 -2
  6. package/ssr/cjs/components/dist/styles/esm/styles-entry.cjs +354 -143
  7. package/ssr/cjs/components/dist/utils/esm/utils-entry.cjs +1 -1
  8. package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/components/popover.wrapper.cjs +5 -4
  9. package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/banner.cjs +15 -5
  10. package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/dialog-base.cjs +3 -7
  11. package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/drilldown.cjs +3 -0
  12. package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/fc-dismiss-button.cjs +16 -0
  13. package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/flyout.cjs +14 -1
  14. package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/inline-notification.cjs +2 -2
  15. package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/modal.cjs +14 -1
  16. package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/popover.cjs +65 -16
  17. package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/sheet.cjs +14 -1
  18. package/ssr/esm/components/dist/styles/esm/styles-entry.mjs +354 -144
  19. package/ssr/esm/components/dist/utils/esm/utils-entry.mjs +1 -1
  20. package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/components/popover.wrapper.mjs +6 -5
  21. package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/banner.mjs +15 -5
  22. package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/dialog-base.mjs +3 -7
  23. package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/drilldown.mjs +3 -0
  24. package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/fc-dismiss-button.mjs +14 -0
  25. package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/flyout.mjs +14 -1
  26. package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/inline-notification.mjs +2 -2
  27. package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/modal.mjs +14 -1
  28. package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/popover.mjs +66 -17
  29. package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/sheet.mjs +14 -1
  30. package/ssr/esm/lib/components/popover.wrapper.d.ts +26 -2
  31. package/ssr/esm/lib/dsr-components/banner.d.ts +2 -0
  32. package/ssr/esm/lib/dsr-components/dialog-base.d.ts +2 -2
  33. package/ssr/esm/lib/dsr-components/drilldown.d.ts +1 -0
  34. package/ssr/esm/lib/dsr-components/fc-dismiss-button.d.ts +16 -0
  35. package/ssr/esm/lib/dsr-components/flyout.d.ts +1 -0
  36. package/ssr/esm/lib/dsr-components/modal.d.ts +1 -0
  37. package/ssr/esm/lib/dsr-components/popover.d.ts +16 -7
  38. package/ssr/esm/lib/dsr-components/sheet.d.ts +1 -0
@@ -3482,7 +3482,7 @@ const hasShowPickerSupport = () => (hasDocument &&
3482
3482
  'showPicker' in HTMLInputElement.prototype &&
3483
3483
  CSS.supports('selector(::-webkit-calendar-picker-indicator)'));
3484
3484
 
3485
- const prefix = `[Porsche Design System v${"4.3.0"}]` // this part isn't covered by unit tests
3485
+ const prefix = `[Porsche Design System v${"4.4.0-rc.1"}]` // this part isn't covered by unit tests
3486
3486
  ;
3487
3487
  const consoleError$1 = (...messages) => {
3488
3488
  console.error(prefix, ...messages);
@@ -7,20 +7,21 @@ var hooks = require('../../hooks.cjs');
7
7
  var utils = require('../../utils.cjs');
8
8
  var popover = require('../dsr-components/popover.cjs');
9
9
 
10
- const PPopover = /*#__PURE__*/ react.forwardRef(({ aria, description, direction = 'bottom', className, children, ...rest }, ref) => {
10
+ const PPopover = /*#__PURE__*/ react.forwardRef(({ aria, compact, description, direction = 'bottom', onDismiss, open, className, children, ...rest }, ref) => {
11
11
  const elementRef = react.useRef(undefined);
12
+ hooks.useEventCallback(elementRef, 'dismiss', onDismiss);
12
13
  const WebComponentTag = hooks.usePrefix('p-popover');
13
- const propsToSync = [aria, description, direction];
14
+ const propsToSync = [aria, compact, description, direction, open];
14
15
  hooks.useBrowserLayoutEffect(() => {
15
16
  const { current } = elementRef;
16
- ['aria', 'description', 'direction'].forEach((propName, i) => (current[propName] = propsToSync[i]));
17
+ ['aria', 'compact', 'description', 'direction', 'open'].forEach((propName, i) => (current[propName] = propsToSync[i]));
17
18
  }, propsToSync);
18
19
  const props = {
19
20
  ...rest,
20
21
  // @ts-ignore
21
22
  ...(!process.browser
22
23
  ? {
23
- children: (jsxRuntime.jsx(popover.DSRPopover, { aria, description, direction, children })),
24
+ children: (jsxRuntime.jsx(popover.DSRPopover, { aria, compact, description, direction, open, children })),
24
25
  }
25
26
  : {
26
27
  children,
@@ -1,14 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
- var react = require('react');
5
- require('../../provider.cjs');
6
4
  var splitChildren = require('../../splitChildren.cjs');
5
+ var react = require('react');
7
6
  var minifyCss = require('../../minifyCss.cjs');
8
7
  var stylesEntry = require('../../../../../../components/dist/styles/esm/styles-entry.cjs');
9
8
  var utilsEntry = require('../../../../../../components/dist/utils/esm/utils-entry.cjs');
9
+ var fcDismissButton = require('./fc-dismiss-button.cjs');
10
10
  var notificationBase = require('./notification-base.cjs');
11
- var button_wrapper = require('../components/button.wrapper.cjs');
12
11
 
13
12
  /**
14
13
  * @slot {"name": "heading", "description": "Defines the heading of the banner. Can be used as an alternative to the `heading` prop for rich content." }
@@ -23,6 +22,12 @@ class DSRBanner extends react.Component {
23
22
  refDismiss;
24
23
  hasHeadingSlot;
25
24
  hasDescriptionSlot;
25
+ // Tracks whether the document-level Escape listener is currently registered (guards the idempotent sync below).
26
+ hasKeydownListener = false;
27
+ // Tracks the component's first render. While `true`, the entry transition (`@starting-style`) is suppressed so an
28
+ // initially-open banner (`open=true` on page load) appears instantly instead of sliding/fading in; flipped to `false`
29
+ // in `componentDidLoad`, so every later (user-triggered) open keeps the entry animation.
30
+ isInitialRender = true;
26
31
  topLayer = utilsEntry.createTopLayerController({
27
32
  getElement: () => this.props.refPopover,
28
33
  isShown: () => !!this.props.refPopover?.matches(':popover-open'),
@@ -35,8 +40,13 @@ class DSRBanner extends react.Component {
35
40
  const hasDescriptionSlot = namedSlotChildren.filter(({ props: { slot } }) => slot === 'description').length > 0;
36
41
  const headingText = this.props.heading ? this.props.heading : namedSlotChildren.find(({ props: { slot } }) => slot === 'heading')?.props.children;
37
42
  const style = minifyCss.minifyCss(stylesEntry.getBannerCss(this.props.open, this.props.position, this.props.state, this.props.dismissButton, !!(this.props.heading || hasHeadingSlot)));
38
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("template", { shadowroot: "open", shadowrootmode: "open", children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsxRuntime.jsx("div", { popover: "manual", "aria-hidden": this.props.open ? 'false' : 'true', ...utilsEntry.getBannerAriaAttributes(this.props.state, headingText), children: jsxRuntime.jsx(notificationBase.NotificationBase, { heading: this.props.heading, headingTag: this.props.headingTag, hasHeadingSlot: hasHeadingSlot, description: this.props.description, hasDescriptionSlot: hasDescriptionSlot, ...(this.props.dismissButton && {
39
- dismissButton: (jsxRuntime.jsx(button_wrapper.PButton, { className: "dismiss", type: "button", variant: "secondary", icon: "close", hideLabel: true, compact: true, ...(headingText ? { aria: { 'aria-description': headingText } } : {}), children: "Close banner" })),
43
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("template", { shadowroot: "open", shadowrootmode: "open", children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: style + (this.props.open ? '[popover]{display:grid!important}' : '') } }), jsxRuntime.jsx("div", { popover: "manual",
44
+ // `inert` (not `aria-hidden`) removes the panel from the a11y tree AND prevents focus while closed / during the
45
+ // fade-out. Using `aria-hidden` here triggers a browser warning when a focusable descendant still holds focus
46
+ // during the closing transition ("Blocked aria-hidden on an element because its descendant retained focus").
47
+ // `inert` avoids that and mirrors the pattern used by `p-modal` / `p-popover` / `p-drilldown`.
48
+ inert: !this.props.open, ...utilsEntry.getBannerAriaAttributes(this.props.state, headingText), children: jsxRuntime.jsx(notificationBase.NotificationBase, { heading: this.props.heading, headingTag: this.props.headingTag, hasHeadingSlot: hasHeadingSlot, description: this.props.description, hasDescriptionSlot: hasDescriptionSlot, ...(this.props.dismissButton && {
49
+ dismissButton: (jsxRuntime.jsx(fcDismissButton.FCDismissButton, { label: "Close banner", ariaDescription: headingText || undefined })),
40
50
  }) }) })] }), this.props.children] }));
41
51
  }
42
52
  }
@@ -1,14 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
- require('react');
5
- require('../../provider.cjs');
6
- var button_wrapper = require('../components/button.wrapper.cjs');
4
+ var fcDismissButton = require('./fc-dismiss-button.cjs');
7
5
 
8
- const DialogBase = ({ children,
9
- // host,
10
- inert, containerClass, ariaAttributes, dismissable = false, header, footer, subFooter, }) => {
11
- return (jsxRuntime.jsx("dialog", { inert: inert, tabIndex: -1, ...(ariaAttributes ?? {}), children: jsxRuntime.jsx("div", { className: "scroller", children: jsxRuntime.jsxs("div", { className: containerClass, children: [dismissable && (jsxRuntime.jsx(button_wrapper.PButton, { className: "dismiss", compact: true, type: "button", hideLabel: true, icon: "close", children: `Dismiss ${containerClass}` })), header, children, footer, subFooter] }) }) }));
6
+ const DialogBase = ({ children, inert, containerClass, ariaAttributes, onMouseDown, dismissable = false, header, footer, subFooter, }) => {
7
+ return (jsxRuntime.jsx("dialog", { inert: inert, tabIndex: -1, ...(ariaAttributes ?? {}), children: jsxRuntime.jsx("div", { className: "scroller", children: jsxRuntime.jsxs("div", { className: containerClass, children: [dismissable && jsxRuntime.jsx(fcDismissButton.FCDismissButton, { label: `Dismiss ${containerClass}` }), header, children, footer, subFooter] }) }) }));
12
8
  };
13
9
 
14
10
  exports.DialogBase = DialogBase;
@@ -26,6 +26,9 @@ class DSRDrilldown extends react.Component {
26
26
  dialog;
27
27
  drawer;
28
28
  isDesktop = false;
29
+ // Tracks whether the current pointer gesture started inside the drawer (not on the backdrop). Lets `onClickDialog`
30
+ // skip dismissal when a selection is dragged out of the drawer and released on the backdrop.
31
+ isPointerDownInside = false;
29
32
  async componentWillLoad() {
30
33
  this.props.defineDrilldownItemElements();
31
34
  const activeItem = this.props.drilldownItemElements.find((item) => item.identifier === this.props.activeIdentifier);
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+
5
+ /**
6
+ * Shared dismiss/close button used across dialog-based (flyout/modal/sheet) and notification-based
7
+ * (banner/inline-notification/toast) components. Renders a native `<button className="dismiss">` with the close icon
8
+ * inlined as a CSS mask (see `fc-dismiss-button-styles.ts`) — so it needs neither a nested `p-button` nor a `p-icon`
9
+ * (avoiding the async CDN icon fetch). Each consumer supplies the variant/positioning styling via the `.dismiss` class.
10
+ * The visible label text is visually hidden but exposed to assistive technology as the accessible name.
11
+ */
12
+ const FCDismissButton = ({ label, ariaDescription, }) => {
13
+ return (jsxRuntime.jsx("button", { className: "dismiss", type: "button", ...(ariaDescription ? { 'aria-description': ariaDescription } : {}), children: jsxRuntime.jsx("span", { children: label }) }));
14
+ };
15
+
16
+ exports.FCDismissButton = FCDismissButton;
@@ -25,6 +25,9 @@ class DSRFlyout extends react.Component {
25
25
  hasHeader;
26
26
  hasFooter;
27
27
  hasSubFooter;
28
+ // Tracks whether the current pointer gesture started inside the panel (not on the backdrop). Lets `onClickDialog`
29
+ // skip dismissal when a selection is dragged out of the panel and released on the backdrop.
30
+ isPointerDownInside = false;
28
31
  topLayer = utilsEntry.createTopLayerController({
29
32
  getElement: () => this.props.dialog,
30
33
  isShown: () => !!this.props.dialog?.open,
@@ -37,7 +40,17 @@ class DSRFlyout extends react.Component {
37
40
  const hasFooter = namedSlotChildren.filter(({ props: { slot } }) => slot === 'footer').length > 0;
38
41
  const hasSubFooter = namedSlotChildren.filter(({ props: { slot } }) => slot === 'sub-footer').length > 0;
39
42
  const style = minifyCss.minifyCss(stylesEntry.getFlyoutCss(this.props.open, this.props.background, this.props.backdrop, this.props.position, hasHeader, hasFooter, hasSubFooter, this.props.footerBehavior, this.props.fullscreen));
40
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("template", { shadowroot: "open", shadowrootmode: "open", children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsxRuntime.jsx(dialogBase.DialogBase, { host: null, dismissable: true, containerClass: "flyout", header: hasHeader ? jsxRuntime.jsx("slot", { name: "header" }) : undefined, footer: hasFooter ? jsxRuntime.jsx("slot", { name: "footer" }) : undefined, subFooter: hasSubFooter ? jsxRuntime.jsx("slot", { name: "sub-footer" }) : undefined, ariaAttributes: utilsEntry.parseAndGetAriaAttributes({
43
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("template", { shadowroot: "open", shadowrootmode: "open", children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsxRuntime.jsx(dialogBase.DialogBase
44
+ // `inert` (not `aria-hidden`) removes the panel from the a11y tree AND prevents focus while closed / during the
45
+ // fade-out. Using `aria-hidden` here triggers a browser warning when a focusable descendant still holds focus
46
+ // during the closing transition ("Blocked aria-hidden on an element because its descendant retained focus").
47
+ // `inert` avoids that and mirrors the pattern used by `p-modal` / `p-popover` / `p-drilldown`.
48
+ , {
49
+ // `inert` (not `aria-hidden`) removes the panel from the a11y tree AND prevents focus while closed / during the
50
+ // fade-out. Using `aria-hidden` here triggers a browser warning when a focusable descendant still holds focus
51
+ // during the closing transition ("Blocked aria-hidden on an element because its descendant retained focus").
52
+ // `inert` avoids that and mirrors the pattern used by `p-modal` / `p-popover` / `p-drilldown`.
53
+ inert: !this.props.open, dismissable: true, containerClass: "flyout", header: hasHeader ? jsxRuntime.jsx("slot", { name: "header" }) : undefined, footer: hasFooter ? jsxRuntime.jsx("slot", { name: "footer" }) : undefined, subFooter: hasSubFooter ? jsxRuntime.jsx("slot", { name: "sub-footer" }) : undefined, ariaAttributes: utilsEntry.parseAndGetAriaAttributes({
41
54
  'aria-modal': true,
42
55
  ...{ 'aria-label': hasHeader ? namedSlotChildren.find(({ props: { slot } }) => slot === 'header')?.props.children : 'Flyout' },
43
56
  ...utilsEntry.parseAndGetAriaAttributes(this.props.aria),
@@ -7,8 +7,8 @@ var splitChildren = require('../../splitChildren.cjs');
7
7
  var minifyCss = require('../../minifyCss.cjs');
8
8
  var stylesEntry = require('../../../../../../components/dist/styles/esm/styles-entry.cjs');
9
9
  var utilsEntry = require('../../../../../../components/dist/utils/esm/utils-entry.cjs');
10
+ var fcDismissButton = require('./fc-dismiss-button.cjs');
10
11
  var notificationBase = require('./notification-base.cjs');
11
- var button_wrapper = require('../components/button.wrapper.cjs');
12
12
  var buttonPure_wrapper = require('../components/button-pure.wrapper.cjs');
13
13
 
14
14
  /**
@@ -26,7 +26,7 @@ class DSRInlineNotification extends react.Component {
26
26
  return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("template", { shadowroot: "open", shadowrootmode: "open", children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsxRuntime.jsx(notificationBase.NotificationBase, { ...utilsEntry.getInlineNotificationAriaAttributes(this.props.state, headingText), heading: this.props.heading, headingTag: this.props.headingTag, hasHeadingSlot: hasHeadingSlot, description: this.props.description, ...(this.props.actionLabel && {
27
27
  actionLabel: (jsxRuntime.jsx(buttonPure_wrapper.PButtonPure, { className: "action", icon: this.props.actionIcon, loading: this.props.actionLoading, children: this.props.actionLabel })),
28
28
  }), ...(this.props.dismissButton && {
29
- dismissButton: (jsxRuntime.jsx(button_wrapper.PButton, { className: "dismiss", type: "button", variant: "secondary", icon: "close", hideLabel: true, compact: true, ...(headingText ? { aria: { 'aria-description': headingText } } : {}), children: "Close notification" })),
29
+ dismissButton: (jsxRuntime.jsx(fcDismissButton.FCDismissButton, { label: "Close notification", ariaDescription: headingText || undefined })),
30
30
  }) })] }), this.props.children] }));
31
31
  }
32
32
  }
@@ -22,6 +22,9 @@ class DSRModal extends react.Component {
22
22
  footer;
23
23
  hasHeader;
24
24
  hasFooter;
25
+ // Tracks whether the current pointer gesture started inside the panel (not on the backdrop). Lets `onClickDialog`
26
+ // skip dismissal when a selection is dragged out of the panel and released on the backdrop.
27
+ isPointerDownInside = false;
25
28
  topLayer = utilsEntry.createTopLayerController({
26
29
  getElement: () => this.props.dialog,
27
30
  isShown: () => !!this.props.dialog?.open,
@@ -35,7 +38,17 @@ class DSRModal extends react.Component {
35
38
  this.props.disableCloseButton ? false : this.props.dismissButton;
36
39
  // TODO: why do we validate only when opened?
37
40
  const style = minifyCss.minifyCss(stylesEntry.getModalCss(this.props.open, this.props.background, this.props.backdrop, this.props.fullscreen, this.props.dismissButton, hasHeader, hasFooter));
38
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("template", { shadowroot: "open", shadowrootmode: "open", children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsxRuntime.jsx(dialogBase.DialogBase, { host: null, inert: !this.props.open, dismissable: this.props.dismissButton ?? undefined, containerClass: "modal", header: hasHeader ? jsxRuntime.jsx("slot", { name: "header" }) : undefined, footer: hasFooter ? jsxRuntime.jsx("slot", { name: "footer" }) : undefined, ariaAttributes: utilsEntry.parseAndGetAriaAttributes({
41
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("template", { shadowroot: "open", shadowrootmode: "open", children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsxRuntime.jsx(dialogBase.DialogBase
42
+ // `inert` (not `aria-hidden`) removes the panel from the a11y tree AND prevents focus while closed / during the
43
+ // fade-out. Using `aria-hidden` here triggers a browser warning when a focusable descendant still holds focus
44
+ // during the closing transition ("Blocked aria-hidden on an element because its descendant retained focus").
45
+ // `inert` avoids that and mirrors the pattern used by `p-flyout` / `p-popover` / `p-drilldown`.
46
+ , {
47
+ // `inert` (not `aria-hidden`) removes the panel from the a11y tree AND prevents focus while closed / during the
48
+ // fade-out. Using `aria-hidden` here triggers a browser warning when a focusable descendant still holds focus
49
+ // during the closing transition ("Blocked aria-hidden on an element because its descendant retained focus").
50
+ // `inert` avoids that and mirrors the pattern used by `p-flyout` / `p-popover` / `p-drilldown`.
51
+ inert: !this.props.open, dismissable: this.props.dismissButton ?? undefined, containerClass: "modal", header: hasHeader ? jsxRuntime.jsx("slot", { name: "header" }) : undefined, footer: hasFooter ? jsxRuntime.jsx("slot", { name: "footer" }) : undefined, ariaAttributes: utilsEntry.parseAndGetAriaAttributes({
39
52
  'aria-modal': true,
40
53
  ...(hasHeader && { 'aria-label': this.props.ariaLabel }),
41
54
  ...utilsEntry.parseAndGetAriaAttributes(this.props.aria),
@@ -1,37 +1,86 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
- var react = require('react');
5
- require('../../provider.cjs');
6
4
  var splitChildren = require('../../splitChildren.cjs');
5
+ var react = require('react');
7
6
  var minifyCss = require('../../minifyCss.cjs');
8
7
  var stylesEntry = require('../../../../../../components/dist/styles/esm/styles-entry.cjs');
9
8
  var utilsEntry = require('../../../../../../components/dist/utils/esm/utils-entry.cjs');
10
- var icon_wrapper = require('../components/icon.wrapper.cjs');
11
9
 
12
10
  /**
13
- * @slot {"name": "", "description": "Default slot for the popover content." }
11
+ * @slot {"name": "", "description": "Default slot for the popover content. Ignored when the `description` prop is set, which takes precedence." }
14
12
  * @slot {"name": "button", "description": "Renders a custom trigger button. When used, the default info button is replaced." }
13
+ *
14
+ * @controlled {"props": ["open"], "event": "dismiss"}
15
15
  */
16
+ // The panel is a native `[popover="manual"]` element that the component promotes to the `#top-layer` itself, so it
17
+ // always renders above surrounding content regardless of ancestor stacking contexts. The component supports two modes:
18
+ // - uncontrolled: `open` is omitted and the component owns visibility via the internal `isOpen` state (toggled by the
19
+ // default info button or a slotted trigger); dismissal closes it directly.
20
+ // - controlled: `open` is a boolean and the consumer owns visibility via a slotted `button`; dismissal only emits
21
+ // `dismiss` and the consumer flips `open`. See `isControlled` / `effectiveOpen` for how the two are reconciled.
16
22
  class DSRPopover extends react.Component {
17
23
  host;
18
24
  isOpen = false;
19
- popover;
20
- button;
21
- slottedButton;
22
- arrow;
25
+ // Tracks the component's first render. While `true`, the entry transition (`@starting-style`) is suppressed so an
26
+ // initially-open popover (`open=true` on page load) appears instantly instead of fading in; flipped to `false` in
27
+ // `componentDidLoad`, so every later (user-triggered) open keeps the fade-in.
28
+ isInitialRender = true;
29
+ // The `[popover]` panel element on the #top-layer that holds the content and the arrow.
30
+ refPopover;
31
+ // The default info button rendered in the Shadow DOM (only present when no `button` slot is used).
32
+ refButton;
33
+ // The `<slot name="button">` element (only present when a custom trigger is projected); its assigned element is the
34
+ // actual trigger, see `triggerElement`.
35
+ refSlotButton;
36
+ // The visual arrow pointing from the panel to the trigger; positioned by Floating UI's `arrow` middleware.
37
+ refArrow;
38
+ // Teardown for the active Floating UI `autoUpdate` subscription; `undefined` while not positioning.
23
39
  cleanUpAutoUpdate;
24
- hasNativePopoverSupport = utilsEntry.getHasNativePopoverSupport();
25
- // TODO: This should be updated when slot is changed
26
- hasSlottedButton;
40
+ // The trigger element `autoUpdate` is currently anchored to, so it can be rebound when the trigger identity changes.
41
+ boundTriggerElement;
42
+ // Tracks whether the document-level dismiss listeners (outside click / Escape / pointer) are currently registered.
43
+ hasDismissListeners = false;
44
+ // Tracks whether a pointer button is currently pressed. Lets `onFocusout` defer pointer-driven focus loss (a click on
45
+ // an outside element, already handled by `onClickOutside`) to that handler, so a single outside pointer interaction
46
+ // emits `dismiss` once instead of twice. `onFocusout` then only dismisses on keyboard focus moves (Tab / Shift+Tab).
47
+ isPointerInteraction = false;
48
+ // Tracks whether the current pointer gesture *started* inside the trigger or panel. A `click` only fires on the
49
+ // nearest common ancestor of `mousedown`/`mouseup`, so pressing inside the panel (e.g. starting a text selection),
50
+ // dragging out and releasing outside retargets the resulting `click` to an ancestor *outside* the popover. Without
51
+ // this flag `onClickOutside` would then wrongly dismiss. Captured at `pointerdown` time (where `composedPath()` is
52
+ // still valid) and consumed on the following `click`, so dismissal only happens when the gesture started outside too.
53
+ isPointerDownInside = false;
54
+ // Keeps the panel on the #top-layer during its fade-out (Chromium via `overlay`; Safari/Firefox via a deferred hide).
55
+ topLayer = utilsEntry.createTopLayerController({
56
+ getElement: () => this.props.refPopover,
57
+ isShown: () => !!this.props.refPopover?.matches(':popover-open'),
58
+ show: () => this.props.refPopover?.showPopover(),
59
+ hide: () => this.props.refPopover?.hidePopover(),
60
+ });
61
+ get isControlled() {
62
+ // Controlled mode is opted into purely by passing a boolean `open`; an omitted (`undefined`) prop means the
63
+ // component manages its own visibility.
64
+ return typeof this.props.open === 'boolean';
65
+ }
66
+ get effectiveOpen() {
67
+ // Single source of truth for "is the panel currently open", regardless of mode: the consumer-owned `open` prop in
68
+ // controlled mode, the internal `isOpen` state otherwise. All render/positioning/dismissal logic reads this.
69
+ return this.props.isControlled ? this.props.open : this.props.isOpen;
70
+ }
71
+ get triggerElement() {
72
+ // Resolves the element that actually acts as the trigger: the default info button in the Shadow DOM, or — when a
73
+ // custom trigger is projected through the `button` slot — the assigned light-DOM element itself (not the `<slot>`).
74
+ // Using the assigned element gives Floating UI an accurate anchor rect and lets `:host` use `display: contents`.
75
+ // Kept correct across dynamic slot changes by the `observeChildren` re-render in `connectedCallback`.
76
+ return this.props.refButton ?? ((this.props.refSlotButton)?.assignedElements()[0]);
77
+ }
27
78
  render() {
28
79
  const { namedSlotChildren} = splitChildren.splitChildren(this.props.children);
29
80
  const hasSlottedButton = namedSlotChildren.filter(({ props: { slot } }) => slot === 'button').length > 0;
30
- const style = minifyCss.minifyCss(stylesEntry.getPopoverCss()).replace(/(:host {[\S\s]+?})[\S\s]+(button {[\S\s]+?})[\S\s]+(.icon {[\S\s]+?})[\S\s]+(.label {[\S\s]+?})[\S\s]+/, '$1\n$2\n$3\n$4');
31
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("template", { shadowroot: "open", shadowrootmode: "open", children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [hasSlottedButton ? (jsxRuntime.jsx("slot", { name: "button" })) : (jsxRuntime.jsxs("button", { type: "button", ...utilsEntry.parseAndGetAriaAttributes({
32
- ...utilsEntry.parseAndGetAriaAttributes(this.props.aria),
33
- ...{ 'aria-expanded': this.props.isOpen },
34
- }), children: [jsxRuntime.jsx(icon_wrapper.PIcon, { className: "icon", name: "information" }), jsxRuntime.jsx("span", { className: "label", children: "More information" })] })), this.props.isOpen && (jsxRuntime.jsxs("div", { popover: "auto", children: [jsxRuntime.jsx("div", { className: "arrow" }), jsxRuntime.jsx("div", { className: "content", children: this.props.description ? jsxRuntime.jsx("p", { children: this.props.description }) : jsxRuntime.jsx("slot", {}) })] }))] })] }), this.props.children] }));
81
+ const id = 'popover';
82
+ const style = minifyCss.minifyCss(stylesEntry.getPopoverCss(this.props.effectiveOpen, this.props.compact, this.props.isInitialRender).replace(/(:host {[\S\s]+?})[\S\s]+(button {[\S\s]+?})[\S\s]+(.icon {[\S\s]+?})[\S\s]+(.label {[\S\s]+?})[\S\s]+/, '$1\n$2\n$3\n$4'));
83
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("template", { shadowroot: "open", shadowrootmode: "open", children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [hasSlottedButton ? (jsxRuntime.jsx("slot", { name: "button" })) : (jsxRuntime.jsx("button", { type: "button", "aria-label": "More information", "aria-details": id, ...utilsEntry.parseAndGetAriaAttributes(this.props.aria), "aria-expanded": this.props.effectiveOpen ? 'true' : 'false' })), jsxRuntime.jsxs("div", { id: id, popover: "manual", inert: !this.props.effectiveOpen, children: [jsxRuntime.jsx("div", { className: "arrow" }), this.props.description ? jsxRuntime.jsx("p", { children: this.props.description }) : jsxRuntime.jsx("slot", {})] })] })] }), this.props.children] }));
35
84
  }
36
85
  }
37
86
 
@@ -19,6 +19,9 @@ class DSRSheet extends react.Component {
19
19
  dialog;
20
20
  scroller;
21
21
  hasHeader;
22
+ // Tracks whether the current pointer gesture started inside the panel (not on the backdrop). Lets `onClickDialog`
23
+ // skip dismissal when a selection is dragged out of the panel and released on the backdrop.
24
+ isPointerDownInside = false;
22
25
  topLayer = utilsEntry.createTopLayerController({
23
26
  getElement: () => this.props.dialog,
24
27
  isShown: () => !!this.props.dialog?.open,
@@ -30,7 +33,17 @@ class DSRSheet extends react.Component {
30
33
  const hasHeader = namedSlotChildren.filter(({ props: { slot } }) => slot === 'header').length > 0;
31
34
  if (this.props.open) ;
32
35
  const style = minifyCss.minifyCss(stylesEntry.getSheetCss(this.props.open, this.props.background, this.props.dismissButton));
33
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("template", { shadowroot: "open", shadowrootmode: "open", children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsxRuntime.jsx(dialogBase.DialogBase, { host: null, inert: !this.props.open, dismissable: this.props.dismissButton ?? undefined, containerClass: "sheet", header: hasHeader ? jsxRuntime.jsx("slot", { name: "header" }) : undefined, ariaAttributes: utilsEntry.parseAndGetAriaAttributes({
36
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("template", { shadowroot: "open", shadowrootmode: "open", children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsxRuntime.jsx(dialogBase.DialogBase
37
+ // `inert` (not `aria-hidden`) removes the panel from the a11y tree AND prevents focus while closed / during the
38
+ // fade-out. Using `aria-hidden` here triggers a browser warning when a focusable descendant still holds focus
39
+ // during the closing transition ("Blocked aria-hidden on an element because its descendant retained focus").
40
+ // `inert` avoids that and mirrors the pattern used by `p-modal` / `p-popover` / `p-drilldown`.
41
+ , {
42
+ // `inert` (not `aria-hidden`) removes the panel from the a11y tree AND prevents focus while closed / during the
43
+ // fade-out. Using `aria-hidden` here triggers a browser warning when a focusable descendant still holds focus
44
+ // during the closing transition ("Blocked aria-hidden on an element because its descendant retained focus").
45
+ // `inert` avoids that and mirrors the pattern used by `p-modal` / `p-popover` / `p-drilldown`.
46
+ inert: !this.props.open, dismissable: this.props.dismissButton ?? undefined, containerClass: "sheet", header: hasHeader ? jsxRuntime.jsx("slot", { name: "header" }) : undefined, ariaAttributes: utilsEntry.parseAndGetAriaAttributes({
34
47
  'aria-modal': true,
35
48
  ...(hasHeader && {
36
49
  'aria-label': namedSlotChildren.filter(({ props: { slot } }) => slot === 'header').length > 0 && namedSlotChildren.find(({ props: { slot } }) => slot === 'header')?.props.children,