reshaped 4.2.0-canary.0 → 4.2.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.
- package/dist/bundle.css +1 -1
- package/dist/bundle.d.ts +6 -0
- package/dist/bundle.js +2 -2
- package/dist/components/Accordion/AccordionContent.js +1 -1
- package/dist/components/Badge/Badge.js +4 -1
- package/dist/components/Badge/Badge.module.css +1 -1
- package/dist/components/Badge/tests/Badge.stories.d.ts +4 -0
- package/dist/components/Badge/tests/Badge.stories.js +48 -1
- package/dist/components/Button/Button.js +2 -0
- package/dist/components/Button/Button.module.css +1 -1
- package/dist/components/Button/tests/Button.stories.js +1 -0
- package/dist/components/ContentToggle/ContentToggle.d.ts +4 -0
- package/dist/components/ContentToggle/ContentToggle.js +12 -0
- package/dist/components/ContentToggle/ContentToggle.module.css +1 -0
- package/dist/components/ContentToggle/ContentToggle.types.d.ts +16 -0
- package/dist/components/ContentToggle/index.d.ts +2 -0
- package/dist/components/ContentToggle/index.js +1 -0
- package/dist/components/ContentToggle/tests/ContentToggle.stories.d.ts +10 -0
- package/dist/components/ContentToggle/tests/ContentToggle.stories.js +75 -0
- package/dist/components/ContextMenu/ContextMenu.js +5 -4
- package/dist/components/ContextMenu/ContextMenu.types.d.ts +5 -1
- package/dist/components/ContextMenu/tests/ContextMenu.stories.d.ts +11 -7
- package/dist/components/ContextMenu/tests/ContextMenu.stories.js +18 -1
- package/dist/components/DropdownMenu/DropdownMenu.context.d.ts +11 -0
- package/dist/components/DropdownMenu/DropdownMenu.context.js +19 -0
- package/dist/components/DropdownMenu/DropdownMenu.js +6 -4
- package/dist/components/DropdownMenu/DropdownMenu.types.d.ts +9 -0
- package/dist/components/DropdownMenu/tests/DropdownMenu.stories.d.ts +1 -0
- package/dist/components/DropdownMenu/tests/DropdownMenu.stories.js +22 -1
- package/dist/components/Expandable/Expandable.d.ts +4 -0
- package/dist/components/Expandable/Expandable.js +85 -0
- package/dist/components/Expandable/Expandable.module.css +1 -0
- package/dist/components/Expandable/Expandable.types.d.ts +18 -0
- package/dist/components/Expandable/Expandable.types.js +1 -0
- package/dist/components/Expandable/index.d.ts +2 -0
- package/dist/components/Expandable/tests/Expandable.stories.d.ts +12 -0
- package/dist/components/Expandable/tests/Expandable.stories.js +82 -0
- package/dist/components/IconToggle/IconToggle.d.ts +4 -0
- package/dist/components/IconToggle/IconToggle.js +13 -0
- package/dist/components/IconToggle/IconToggle.module.css +1 -0
- package/dist/components/IconToggle/IconToggle.types.d.ts +5 -0
- package/dist/components/IconToggle/IconToggle.types.js +1 -0
- package/dist/components/IconToggle/index.d.ts +2 -0
- package/dist/components/IconToggle/index.js +1 -0
- package/dist/components/IconToggle/tests/IconToggle.stories.d.ts +10 -0
- package/dist/components/IconToggle/tests/IconToggle.stories.js +24 -0
- package/dist/components/Image/Image.js +14 -0
- package/dist/components/Link/Link.d.ts +1 -1
- package/dist/components/Link/Link.js +2 -2
- package/dist/components/Link/Link.types.d.ts +1 -1
- package/dist/components/Link/tests/Link.stories.d.ts +2 -1
- package/dist/components/Link/tests/Link.stories.js +7 -1
- package/dist/components/MenuItem/MenuItem.js +14 -2
- package/dist/components/MenuItem/MenuItem.module.css +1 -1
- package/dist/components/Select/Select.module.css +1 -1
- package/dist/components/Select/SelectStartContent.js +2 -0
- package/dist/components/Tabs/Tabs.module.css +1 -1
- package/dist/components/Tabs/TabsItem.js +6 -1
- package/dist/components/TextField/TextField.js +2 -0
- package/dist/components/TextField/TextField.module.css +1 -1
- package/dist/components/_private/Presence/Presence.d.ts +7 -0
- package/dist/components/_private/Presence/Presence.js +71 -0
- package/dist/components/_private/Presence/Presence.module.css +1 -0
- package/dist/components/_private/Presence/Presence.types.d.ts +45 -0
- package/dist/components/_private/Presence/Presence.types.js +1 -0
- package/dist/components/_private/Presence/index.d.ts +1 -0
- package/dist/components/_private/Presence/index.js +1 -0
- package/dist/hooks/_internal/useSingletonHotkeys.d.ts +2 -2
- package/dist/hooks/_internal/useSingletonHotkeys.js +102 -76
- package/dist/hooks/_internal/useSingletonKeyboardMode.js +12 -0
- package/dist/hooks/useOnClickOutside.js +19 -11
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3 -0
- package/package.json +3 -3
- package/dist/components/_private/Expandable/Expandable.d.ts +0 -4
- package/dist/components/_private/Expandable/Expandable.js +0 -58
- package/dist/components/_private/Expandable/Expandable.module.css +0 -1
- package/dist/components/_private/Expandable/Expandable.types.d.ts +0 -7
- package/dist/components/_private/Expandable/index.d.ts +0 -1
- /package/dist/components/{_private/Expandable/Expandable.types.js → ContentToggle/ContentToggle.types.js} +0 -0
- /package/dist/components/{_private/Expandable → Expandable}/index.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
.root{--rs-p-h:var(--rs-text-field-p-h);--rs-p-v:0px;--rs-text-field-start-slot-padding:var(--rs-unit-x2);--rs-text-field-end-slot-padding:var(--rs-unit-x2);--rs-text-field-focus-border-color:var(--rs-color-border-primary);display:flex;align-items:center;position:relative;z-index:0;background:var(--rs-color-background-elevation-base);border-radius:var(--rs-text-field-radius);padding:var(--rs-unit-x1) var(--rs-text-field-p-h);min-height:var(--rs-text-field-min-height)}.root.--focused,.root:has(.icon:active),.root:not(:has(button:focus,a:focus,[tabindex="0"]:focus,[role=button]:focus,select:focus)):focus-within{box-shadow:var(--rs-outline-shadow)}.root.--multiline{flex-wrap:wrap}.root.--multiline .input{width:auto}.root.--rounded{--rs-text-field-radius:var(--rs-radius-circular)}.inner{display:inline-flex;flex-grow:1}.input{border:none;outline:none;position:relative;z-index:1;background:none;flex-grow:1;box-sizing:border-box;width:100%;color:var(--rs-color-foreground-neutral);min-height:var(--rs-text-field-min-height);margin:calc(var(--rs-text-field-p-v) * -1) calc(var(--rs-text-field-gap) * -1);padding-inline:var(--rs-text-field-gap);padding-block:0;font-weight:var(--rs-font-weight-regular);font-family:var(--rs-font-family-body)}.input:-webkit-autofill{-webkit-background-clip:text;-webkit-text-fill-color:var(--rs-color-foreground-neutral)}.affix,.input{font-size:var(--rs-text-field-font-size);line-height:var(--rs-text-field-line-height);letter-spacing:var(--rs-text-field-letter-spacing)}.affix,.icon,.slot{max-width:100%;position:relative;z-index:5;display:flex;align-items:center;flex-shrink:0;min-height:calc(var(--rs-text-field-min-height) - var(--rs-unit-x2))}.affix--position-start,.icon--position-start,.slot--position-start{margin-inline-end:var(--rs-text-field-gap)}.affix--position-end,.icon--position-end,.slot--position-end{margin-inline-start:var(--rs-text-field-gap)}.icon{cursor:text}.icon.icon--position-start{margin-inline-start:calc(var(--rs-text-field-icon-align) * -1)}.icon.icon--position-end{margin-inline-end:calc(var(--rs-text-field-icon-align) * -1)}.slot.slot--position-start{--rs-text-field-slot-adjustment:calc(var(--rs-text-field-start-slot-padding) - var(--rs-text-field-p-h));margin-inline-start:var(--rs-text-field-slot-adjustment)}.icon+.slot.slot--position-start{margin-inline-start:0}.slot.slot--position-start:has(+.slot--position-start){margin-inline-end:calc(max(calc(var(--rs-text-field-slot-adjustment) * -1), 0px) + var(--rs-text-field-gap))}.slot.slot--position-end{--rs-text-field-slot-adjustment:calc(var(--rs-text-field-end-slot-padding) - var(--rs-text-field-p-h));margin-inline-end:var(--rs-text-field-slot-adjustment)}.affix{color:var(--rs-color-foreground-neutral-faded)}.affix.affix--position-start{padding-inline-end:calc(var(--rs-text-field-gap) + 1px)}.affix.affix--position-start:after{content:"";position:absolute;inset-block:var(--rs-unit-x1-5);inset-inline-end:0;border-inline-end:1px solid var(--rs-color-border-neutral-faded)}.affix.affix--position-end{padding-inline-start:calc(var(--rs-text-field-gap) + 1px)}.affix.affix--position-end:after{content:"";position:absolute;inset-block:var(--rs-unit-x1-5);inset-inline-start:0;border-inline-start:1px solid var(--rs-color-border-neutral-faded)}.input+.affix--position-end,.input+.icon--position-end,.input+.slot--position-end{margin-inline-start:auto}.root.--disabled{--rs-text-field-border-color:var(--rs-color-border-disabled);background:var(--rs-color-background-disabled-faded)}.root.--disabled,.root.--disabled .input{color:var(--rs-color-foreground-disabled);cursor:not-allowed}.--size-small{--rs-text-field-gap:var(--rs-unit-x1-5);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:calc(var(--rs-unit-x1) + (var(--rs-line-height-body-2) - var(--rs-line-height-caption-1)) / 2);--rs-text-field-p-h:var(--rs-unit-x2);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-caption-1);--rs-text-field-line-height:var(--rs-line-height-caption-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-caption-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-text-field-p-v) * 2)}.--size-medium{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-p-h:var(--rs-unit-x3);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x2) * 2)}.--size-large{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-p-h:var(--rs-unit-x4);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x2);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x3) * 2)}.--size-xlarge{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-p-h:var(--rs-unit-x5);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) * 2)}.root.--variant-faded{background:var(--rs-color-background-neutral-faded)}.root.--variant-ghost{background:transparent}.root.--variant-headless{--rs-text-field-focus-border-color:transparent;background:transparent;box-shadow:none!important}.root.--status-error:not(.--variant-headless){box-shadow:0 0 0 var(--rs-outline-width) var(--rs-color-border-critical) inset}@media (--rs-viewport-s ) and (hover:none){.input{font-size:var(--rs-font-size-body-1)!important}}@media (--rs-viewport-m ){.--size-small--m{--rs-text-field-gap:var(--rs-unit-x1-5);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:calc(var(--rs-unit-x1) + (var(--rs-line-height-body-2) - var(--rs-line-height-caption-1)) / 2);--rs-text-field-p-h:var(--rs-unit-x2);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-caption-1);--rs-text-field-line-height:var(--rs-line-height-caption-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-caption-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-text-field-p-v) * 2)}.--size-medium--m{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-p-h:var(--rs-unit-x3);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x2) * 2)}.--size-large--m{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-p-h:var(--rs-unit-x4);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x2);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x3) * 2)}.--size-xlarge--m{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-p-h:var(--rs-unit-x5);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) * 2)}}@media (--rs-viewport-l ){.--size-small--l{--rs-text-field-gap:var(--rs-unit-x1-5);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:calc(var(--rs-unit-x1) + (var(--rs-line-height-body-2) - var(--rs-line-height-caption-1)) / 2);--rs-text-field-p-h:var(--rs-unit-x2);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-caption-1);--rs-text-field-line-height:var(--rs-line-height-caption-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-caption-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-text-field-p-v) * 2)}.--size-medium--l{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-p-h:var(--rs-unit-x3);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x2) * 2)}.--size-large--l{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-p-h:var(--rs-unit-x4);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x2);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x3) * 2)}.--size-xlarge--l{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-p-h:var(--rs-unit-x5);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) * 2)}}@media (--rs-viewport-xl ){.--size-small--xl{--rs-text-field-gap:var(--rs-unit-x1-5);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:calc(var(--rs-unit-x1) + (var(--rs-line-height-body-2) - var(--rs-line-height-caption-1)) / 2);--rs-text-field-p-h:var(--rs-unit-x2);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-caption-1);--rs-text-field-line-height:var(--rs-line-height-caption-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-caption-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-text-field-p-v) * 2)}.--size-medium--xl{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-p-h:var(--rs-unit-x3);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x2) * 2)}.--size-large--xl{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-p-h:var(--rs-unit-x4);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x2);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x3) * 2)}.--size-xlarge--xl{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-p-h:var(--rs-unit-x5);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) * 2)}}
|
|
1
|
+
.root{--rs-p-h:var(--rs-text-field-p-h);--rs-p-v:0px;--rs-text-field-start-slot-padding:var(--rs-unit-x2);--rs-text-field-end-slot-padding:var(--rs-unit-x2);--rs-text-field-focus-border-color:var(--rs-color-border-primary);display:flex;align-items:center;position:relative;z-index:0;background:var(--rs-color-background-elevation-base);border-radius:var(--rs-text-field-radius);padding:var(--rs-unit-x1) var(--rs-text-field-p-h);min-height:var(--rs-text-field-min-height)}.root.--focused,.root:has(.icon:active),.root:not(:has(button:focus,a:focus,[tabindex="0"]:focus,[role=button]:focus,select:focus)):focus-within{box-shadow:var(--rs-outline-shadow)}.root.--multiline{flex-wrap:wrap}.root.--multiline .input{width:auto}.root.--rounded{--rs-text-field-radius:var(--rs-radius-circular)}.inner{display:inline-flex;flex-grow:1}.input{border:none;outline:none;position:relative;z-index:1;background:none;flex-grow:1;box-sizing:border-box;width:100%;color:var(--rs-color-foreground-neutral);min-height:var(--rs-text-field-min-height);margin:calc(var(--rs-text-field-p-v) * -1) calc(var(--rs-text-field-gap) * -1);padding-inline:var(--rs-text-field-gap);padding-block:0;font-weight:var(--rs-font-weight-regular);font-family:var(--rs-font-family-body)}.input:-webkit-autofill{-webkit-background-clip:text;-webkit-text-fill-color:var(--rs-color-foreground-neutral)}.affix,.input{font-size:var(--rs-text-field-font-size);line-height:var(--rs-text-field-line-height);letter-spacing:var(--rs-text-field-letter-spacing)}.affix,.icon,.slot{max-width:100%;position:relative;z-index:5;display:flex;align-items:center;flex-shrink:0;min-height:calc(var(--rs-text-field-min-height) - var(--rs-unit-x2))}.affix--position-start,.icon--position-start,.slot--position-start{margin-inline-end:var(--rs-text-field-gap)}.affix--position-end,.icon--position-end,.slot--position-end{margin-inline-start:var(--rs-text-field-gap)}.icon{cursor:text}.icon.icon--position-start{margin-inline-start:calc(var(--rs-text-field-icon-align) * -1)}.icon.icon--position-end{margin-inline-end:calc(var(--rs-text-field-icon-align) * -1)}.slot.slot--position-start{--rs-text-field-slot-adjustment:calc(var(--rs-text-field-start-slot-padding) - var(--rs-text-field-p-h));margin-inline-start:var(--rs-text-field-slot-adjustment)}.icon+.slot.slot--position-start{margin-inline-start:0}.slot.slot--position-start:has(+.slot--position-start){margin-inline-end:calc(max(calc(var(--rs-text-field-slot-adjustment) * -1), 0px) + var(--rs-text-field-gap))}.slot.slot--position-end{--rs-text-field-slot-adjustment:calc(var(--rs-text-field-end-slot-padding) - var(--rs-text-field-p-h));margin-inline-end:var(--rs-text-field-slot-adjustment)}.affix{color:var(--rs-color-foreground-neutral-faded)}.affix.affix--position-start{padding-inline-end:calc(var(--rs-text-field-gap) + 1px)}.affix.affix--position-start:after{content:"";position:absolute;inset-block:var(--rs-unit-x1-5);inset-inline-end:0;border-inline-end:1px solid var(--rs-color-border-neutral-faded)}.affix.affix--position-end{padding-inline-start:calc(var(--rs-text-field-gap) + 1px)}.affix.affix--position-end:after{content:"";position:absolute;inset-block:var(--rs-unit-x1-5);inset-inline-start:0;border-inline-start:1px solid var(--rs-color-border-neutral-faded)}.input+.affix--position-end,.input+.icon--position-end,.input+.slot--position-end{margin-inline-start:auto}.root.--disabled{--rs-text-field-border-color:var(--rs-color-border-disabled);background:var(--rs-color-background-disabled-faded)}.root.--disabled,.root.--disabled .input{color:var(--rs-color-foreground-disabled);cursor:not-allowed}.--size-small{--rs-text-field-gap:var(--rs-unit-x1);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:calc(var(--rs-unit-x1) + (var(--rs-line-height-body-2) - var(--rs-line-height-caption-1)) / 2);--rs-text-field-p-h:var(--rs-unit-x2);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-caption-1);--rs-text-field-line-height:var(--rs-line-height-caption-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-caption-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-text-field-p-v) * 2)}.--size-medium{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-p-h:var(--rs-unit-x3);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x2) * 2)}.--size-large{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-p-h:var(--rs-unit-x4);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x2);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x3) * 2)}.--size-xlarge{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-p-h:var(--rs-unit-x5);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) * 2)}.root.--variant-faded{background:var(--rs-color-background-neutral-faded)}.root.--variant-ghost{background:transparent}.root.--variant-headless{--rs-text-field-focus-border-color:transparent;background:transparent;box-shadow:none!important}.root.--status-error:not(.--variant-headless){box-shadow:0 0 0 var(--rs-outline-width) var(--rs-color-border-critical) inset}@media (--rs-viewport-s ) and (hover:none){.input{font-size:var(--rs-font-size-body-1)!important}}@media (--rs-viewport-m ){.--size-small--m{--rs-text-field-gap:var(--rs-unit-x1);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:calc(var(--rs-unit-x1) + (var(--rs-line-height-body-2) - var(--rs-line-height-caption-1)) / 2);--rs-text-field-p-h:var(--rs-unit-x2);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-caption-1);--rs-text-field-line-height:var(--rs-line-height-caption-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-caption-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-text-field-p-v) * 2)}.--size-medium--m{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-p-h:var(--rs-unit-x3);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x2) * 2)}.--size-large--m{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-p-h:var(--rs-unit-x4);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x2);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x3) * 2)}.--size-xlarge--m{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-p-h:var(--rs-unit-x5);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) * 2)}}@media (--rs-viewport-l ){.--size-small--l{--rs-text-field-gap:var(--rs-unit-x1);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:calc(var(--rs-unit-x1) + (var(--rs-line-height-body-2) - var(--rs-line-height-caption-1)) / 2);--rs-text-field-p-h:var(--rs-unit-x2);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-caption-1);--rs-text-field-line-height:var(--rs-line-height-caption-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-caption-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-text-field-p-v) * 2)}.--size-medium--l{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-p-h:var(--rs-unit-x3);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x2) * 2)}.--size-large--l{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-p-h:var(--rs-unit-x4);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x2);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x3) * 2)}.--size-xlarge--l{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-p-h:var(--rs-unit-x5);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) * 2)}}@media (--rs-viewport-xl ){.--size-small--xl{--rs-text-field-gap:var(--rs-unit-x1);--rs-text-field-radius:var(--rs-radius-small);--rs-text-field-p-v:calc(var(--rs-unit-x1) + (var(--rs-line-height-body-2) - var(--rs-line-height-caption-1)) / 2);--rs-text-field-p-h:var(--rs-unit-x2);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-caption-1);--rs-text-field-line-height:var(--rs-line-height-caption-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-caption-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-text-field-p-v) * 2)}.--size-medium--xl{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x2);--rs-text-field-p-h:var(--rs-unit-x3);--rs-text-field-icon-align:var(--rs-unit-x0-5);--rs-text-field-font-size:var(--rs-font-size-body-2);--rs-text-field-line-height:var(--rs-line-height-body-2);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-2);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x2) * 2)}.--size-large--xl{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x3);--rs-text-field-p-h:var(--rs-unit-x4);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x2);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x3) * 2)}.--size-xlarge--xl{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-radius:var(--rs-radius-medium);--rs-text-field-p-v:var(--rs-unit-x4);--rs-text-field-p-h:var(--rs-unit-x5);--rs-text-field-icon-align:var(--rs-unit-x1);--rs-text-field-font-size:var(--rs-font-size-body-1);--rs-text-field-line-height:var(--rs-line-height-body-1);--rs-text-field-letter-spacing:var(--rs-letter-spacing-body-1);--rs-text-field-action-inset:var(--rs-unit-x1);--rs-text-field-min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x4) * 2)}}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type * as T from "./Presence.types";
|
|
3
|
+
declare function Presence<As extends keyof React.JSX.IntrinsicElements = "span">(props: T.Props<As>): React.JSX.Element;
|
|
4
|
+
declare namespace Presence {
|
|
5
|
+
var displayName: string;
|
|
6
|
+
}
|
|
7
|
+
export default Presence;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { classNames } from "@reshaped/utilities";
|
|
5
|
+
import useIsomorphicLayoutEffect from "../../../hooks/useIsomorphicLayoutEffect";
|
|
6
|
+
import s from "./Presence.module.css";
|
|
7
|
+
const PresenceItem = (props) => {
|
|
8
|
+
const { as, entry, status, itemClassName, enterClassName, exitClassName, onExited } = props;
|
|
9
|
+
// Rendering a union of every intrinsic tag name blows up the JSX prop type
|
|
10
|
+
const TagName = as;
|
|
11
|
+
const elRef = React.useRef(null);
|
|
12
|
+
const itemClassNames = classNames(s.item, status && s[`--${status}`], itemClassName, status === "enter" && enterClassName, status === "exit" && exitClassName);
|
|
13
|
+
const handleAnimationEnd = (e) => {
|
|
14
|
+
if (status !== "exit" || e.target !== elRef.current)
|
|
15
|
+
return;
|
|
16
|
+
onExited(entry.id);
|
|
17
|
+
};
|
|
18
|
+
// Exiting items are removed when their animation ends, so the ones that never
|
|
19
|
+
// start it have to be released here. Reduced motion keeps the animation and only
|
|
20
|
+
// zeroes its duration, which makes it end on the next frame instead
|
|
21
|
+
useIsomorphicLayoutEffect(() => {
|
|
22
|
+
const el = elRef.current;
|
|
23
|
+
if (status !== "exit" || !el)
|
|
24
|
+
return;
|
|
25
|
+
if (el.getAnimations().length > 0)
|
|
26
|
+
return;
|
|
27
|
+
onExited(entry.id);
|
|
28
|
+
}, [status, entry.id, onExited]);
|
|
29
|
+
return (_jsx(TagName, { ref: elRef, className: itemClassNames, "aria-hidden": status === "exit" || undefined, onAnimationEnd: handleAnimationEnd, children: entry.children }));
|
|
30
|
+
};
|
|
31
|
+
const Presence = (props) => {
|
|
32
|
+
const { children, itemKey, as: TagName = "span", className, itemClassName, enterClassName, exitClassName, attributes, } = props;
|
|
33
|
+
const idRef = React.useRef(0);
|
|
34
|
+
// Holds the children of the last committed render, which become the exiting ones on a key change
|
|
35
|
+
const childrenRef = React.useRef(children);
|
|
36
|
+
const [state, setState] = React.useState(() => ({ id: 0, key: itemKey, exiting: [] }));
|
|
37
|
+
// Rendering both children at the same time has to happen in the same pass as the key change,
|
|
38
|
+
// otherwise the previous children get unmounted before we can animate them out
|
|
39
|
+
if (state.key !== itemKey) {
|
|
40
|
+
idRef.current += 1;
|
|
41
|
+
setState({
|
|
42
|
+
id: idRef.current,
|
|
43
|
+
key: itemKey,
|
|
44
|
+
status: "enter",
|
|
45
|
+
exiting: [
|
|
46
|
+
// An item swapped back in before it finished exiting is replaced by the new one
|
|
47
|
+
...state.exiting.filter((entry) => entry.key !== itemKey),
|
|
48
|
+
{ id: state.id, key: state.key, children: childrenRef.current },
|
|
49
|
+
],
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const handleExited = React.useCallback((id) => {
|
|
53
|
+
setState((prevState) => ({
|
|
54
|
+
...prevState,
|
|
55
|
+
exiting: prevState.exiting.filter((entry) => entry.id !== id),
|
|
56
|
+
}));
|
|
57
|
+
}, []);
|
|
58
|
+
useIsomorphicLayoutEffect(() => {
|
|
59
|
+
childrenRef.current = children;
|
|
60
|
+
});
|
|
61
|
+
const itemProps = {
|
|
62
|
+
as: TagName,
|
|
63
|
+
itemClassName,
|
|
64
|
+
enterClassName,
|
|
65
|
+
exitClassName,
|
|
66
|
+
onExited: handleExited,
|
|
67
|
+
};
|
|
68
|
+
return (_jsxs(TagName, { ...attributes, className: classNames(s.root, className), children: [state.exiting.map((entry) => (_jsx(PresenceItem, { entry: entry, status: "exit", ...itemProps }, entry.id))), _jsx(PresenceItem, { entry: { id: state.id, key: itemKey, children }, status: state.status, ...itemProps }, state.id)] }));
|
|
69
|
+
};
|
|
70
|
+
Presence.displayName = "Presence";
|
|
71
|
+
export default Presence;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.root{display:grid;grid-template-areas:"presence"}.item{grid-area:presence;min-width:0}.--exit{pointer-events:none}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
import type { ClassName } from "@reshaped/utilities";
|
|
3
|
+
import type { Attributes } from "../../../types/global";
|
|
4
|
+
export type Status = "enter" | "exit";
|
|
5
|
+
export type Entry = {
|
|
6
|
+
id: number;
|
|
7
|
+
key: unknown;
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
};
|
|
10
|
+
export type State = {
|
|
11
|
+
/** Id of the currently rendered entry */
|
|
12
|
+
id: number;
|
|
13
|
+
/** Key the currently rendered entry was rendered with */
|
|
14
|
+
key: unknown;
|
|
15
|
+
/** Undefined until the first swap happens to avoid animating on mount */
|
|
16
|
+
status?: Status;
|
|
17
|
+
/** Entries kept mounted until their exit animation ends */
|
|
18
|
+
exiting: Entry[];
|
|
19
|
+
};
|
|
20
|
+
export type ItemProps = Pick<Props, "itemClassName" | "enterClassName" | "exitClassName"> & {
|
|
21
|
+
as: keyof React.JSX.IntrinsicElements;
|
|
22
|
+
entry: Entry;
|
|
23
|
+
status?: Status;
|
|
24
|
+
onExited: (id: number) => void;
|
|
25
|
+
};
|
|
26
|
+
export type Props<TagName extends keyof React.JSX.IntrinsicElements | void = void> = {
|
|
27
|
+
children?: React.ReactNode;
|
|
28
|
+
/**
|
|
29
|
+
* Identity of the current children, compared by reference.
|
|
30
|
+
* Changing it renders the previous and the next children at the same time
|
|
31
|
+
*/
|
|
32
|
+
itemKey: unknown;
|
|
33
|
+
/** Render the root and every item as a different element */
|
|
34
|
+
as?: TagName extends keyof React.JSX.IntrinsicElements ? TagName : keyof React.JSX.IntrinsicElements;
|
|
35
|
+
/** Additional classname for the root element */
|
|
36
|
+
className?: ClassName;
|
|
37
|
+
/** Classname of every rendered item */
|
|
38
|
+
itemClassName?: ClassName;
|
|
39
|
+
/** Classname of the item animating in, added on every change except the first render */
|
|
40
|
+
enterClassName?: ClassName;
|
|
41
|
+
/** Classname of the item animating out, the item is removed when its animation ends */
|
|
42
|
+
exitClassName?: ClassName;
|
|
43
|
+
/** Additional attributes for the root element */
|
|
44
|
+
attributes?: Attributes<TagName>;
|
|
45
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./Presence";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./Presence";
|
|
@@ -20,8 +20,8 @@ type HotkeyData = {
|
|
|
20
20
|
export declare class HotkeyStore {
|
|
21
21
|
hotkeyMap: Record<string, Set<HotkeyData>>;
|
|
22
22
|
getSize: () => number;
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
hasHandlers: (pressedId: string) => boolean;
|
|
24
|
+
bindHotkeys: (hotkeys: Hotkeys, ref: React.RefObject<HTMLElement | null>, options: HotkeyOptions) => () => void;
|
|
25
25
|
handleKeyDown: (pressedMap: PressedMap, e: KeyboardEvent) => void;
|
|
26
26
|
}
|
|
27
27
|
export declare const SingletonHotkeysProvider: React.FC<{
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import React from "react";
|
|
4
4
|
/**
|
|
5
5
|
* Utilities
|
|
6
6
|
*/
|
|
7
7
|
const COMBINATION_DELIMETER = "+";
|
|
8
|
-
|
|
8
|
+
const MODIFIER_KEYS = ["meta", "control", "alt", "shift"];
|
|
9
9
|
const formatHotkey = (hotkey) => {
|
|
10
10
|
if (hotkey === " ")
|
|
11
11
|
return hotkey;
|
|
@@ -19,11 +19,26 @@ const getEventKey = (e) => {
|
|
|
19
19
|
if (!e.key)
|
|
20
20
|
return;
|
|
21
21
|
// Having alt pressed modifies e.key value, so relying on e.code for it
|
|
22
|
-
if (e.altKey && /^
|
|
23
|
-
return e.code.toLowerCase().replace(
|
|
22
|
+
if (e.altKey && /^(Key|Digit|Numpad)/.test(e.code)) {
|
|
23
|
+
return e.code.toLowerCase().replace(/^(key|digit|numpad)/, "");
|
|
24
24
|
}
|
|
25
25
|
return e.key.toLowerCase();
|
|
26
26
|
};
|
|
27
|
+
/**
|
|
28
|
+
* Support for `mod` that represents both Mac and Win keyboards
|
|
29
|
+
* We create the hotkeyId again to sort the mod key correctly
|
|
30
|
+
*/
|
|
31
|
+
const getPressedIds = (pressedId) => {
|
|
32
|
+
const pressedFormattedKeys = pressedId.split(COMBINATION_DELIMETER);
|
|
33
|
+
const ids = [pressedId];
|
|
34
|
+
if (pressedFormattedKeys.includes("control")) {
|
|
35
|
+
ids.push(getHotkeyId(pressedId.replace("control", "mod")));
|
|
36
|
+
}
|
|
37
|
+
if (pressedFormattedKeys.includes("meta")) {
|
|
38
|
+
ids.push(getHotkeyId(pressedId.replace("meta", "mod")));
|
|
39
|
+
}
|
|
40
|
+
return ids;
|
|
41
|
+
};
|
|
27
42
|
// Removing the unknown gets highlighted an invalid syntax
|
|
28
43
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint
|
|
29
44
|
const walkHotkeys = (hotkeys, cb) => {
|
|
@@ -39,63 +54,50 @@ const walkHotkeys = (hotkeys, cb) => {
|
|
|
39
54
|
export class HotkeyStore {
|
|
40
55
|
hotkeyMap = {};
|
|
41
56
|
getSize = () => Object.keys(this.hotkeyMap).length;
|
|
57
|
+
hasHandlers = (pressedId) => {
|
|
58
|
+
return getPressedIds(pressedId).some((id) => this.hotkeyMap[id]?.size);
|
|
59
|
+
};
|
|
42
60
|
bindHotkeys = (hotkeys, ref, options) => {
|
|
43
|
-
|
|
44
|
-
|
|
61
|
+
const boundData = [];
|
|
62
|
+
walkHotkeys(hotkeys, (id, callback) => {
|
|
63
|
+
if (!callback)
|
|
45
64
|
return;
|
|
65
|
+
const data = { callback, ref, options };
|
|
46
66
|
if (!this.hotkeyMap[id]) {
|
|
47
67
|
this.hotkeyMap[id] = new Set();
|
|
48
68
|
}
|
|
49
|
-
this.hotkeyMap[id].add(
|
|
69
|
+
this.hotkeyMap[id].add(data);
|
|
70
|
+
boundData.push({ id, data });
|
|
50
71
|
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
this.hotkeyMap[id]?.forEach((data) => {
|
|
57
|
-
if (data.callback === hotkeyCallback) {
|
|
58
|
-
this.hotkeyMap[id].delete(data);
|
|
72
|
+
return () => {
|
|
73
|
+
boundData.forEach(({ id, data }) => {
|
|
74
|
+
this.hotkeyMap[id]?.delete(data);
|
|
75
|
+
if (!this.hotkeyMap[id]?.size) {
|
|
76
|
+
delete this.hotkeyMap[id];
|
|
59
77
|
}
|
|
60
78
|
});
|
|
61
|
-
|
|
62
|
-
delete this.hotkeyMap[id];
|
|
63
|
-
}
|
|
64
|
-
});
|
|
79
|
+
};
|
|
65
80
|
};
|
|
66
81
|
handleKeyDown = (pressedMap, e) => {
|
|
67
82
|
const pressedKeys = Object.keys(pressedMap);
|
|
68
83
|
if (!pressedKeys.length)
|
|
69
84
|
return;
|
|
70
85
|
const pressedId = getHotkeyId(pressedKeys.join(COMBINATION_DELIMETER));
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
* We create the hotkeyId again to sort the mod key correctly
|
|
76
|
-
*/
|
|
77
|
-
const controlToModPressedId = getHotkeyId(pressedId.replace("control", "mod"));
|
|
78
|
-
const metaToModPressedId = getHotkeyId(pressedId.replace("meta", "mod"));
|
|
79
|
-
const hotkeyControlModData = pressedFormattedKeys.includes("control") && this.hotkeyMap[controlToModPressedId];
|
|
80
|
-
const hotkeyMetaModData = pressedFormattedKeys.includes("meta") && this.hotkeyMap[metaToModPressedId];
|
|
81
|
-
[hotkeyData, hotkeyControlModData, hotkeyMetaModData].forEach((hotkeyData) => {
|
|
82
|
-
if (!hotkeyData)
|
|
86
|
+
const eventTarget = e.composedPath()[0];
|
|
87
|
+
getPressedIds(pressedId).forEach((id) => {
|
|
88
|
+
const hotkeyData = this.hotkeyMap[id];
|
|
89
|
+
if (!hotkeyData?.size)
|
|
83
90
|
return;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
e.preventDefault();
|
|
95
|
-
}
|
|
96
|
-
data.callback(e);
|
|
97
|
-
});
|
|
98
|
-
}
|
|
91
|
+
hotkeyData.forEach((data) => {
|
|
92
|
+
if (data.ref.current &&
|
|
93
|
+
!(eventTarget === data.ref.current || data.ref.current.contains(eventTarget))) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (data.options.preventDefault) {
|
|
97
|
+
e.preventDefault();
|
|
98
|
+
}
|
|
99
|
+
data.callback(e);
|
|
100
|
+
});
|
|
99
101
|
});
|
|
100
102
|
};
|
|
101
103
|
}
|
|
@@ -104,61 +106,76 @@ const globalHotkeyStore = new HotkeyStore();
|
|
|
104
106
|
* Components / Hooks
|
|
105
107
|
*/
|
|
106
108
|
const HotkeyContext = React.createContext({});
|
|
107
|
-
|
|
109
|
+
const HotkeysProvider = (props) => {
|
|
108
110
|
const { children } = props;
|
|
109
|
-
|
|
111
|
+
// Ref is the source of truth to keep the map in sync with the native events,
|
|
112
|
+
// state is mirroring it to re-render the consumers relying on isPressed
|
|
113
|
+
const pressedMapRef = React.useRef({});
|
|
114
|
+
const [, setPressedState] = React.useState({});
|
|
115
|
+
// Keyup events don't trigger for regular keys while Meta is pressed on macOS,
|
|
116
|
+
// so we track the keys pressed during that time to release them manually
|
|
117
|
+
const metaModifiedKeysRef = React.useRef([]);
|
|
110
118
|
const hooksCountRef = React.useRef(0);
|
|
119
|
+
const setPressedMap = React.useCallback((nextPressedMap) => {
|
|
120
|
+
pressedMapRef.current = nextPressedMap;
|
|
121
|
+
setPressedState(nextPressedMap);
|
|
122
|
+
}, []);
|
|
111
123
|
const addPressedKey = React.useCallback((e) => {
|
|
112
124
|
if (e.repeat || hooksCountRef.current === 0)
|
|
113
125
|
return;
|
|
114
126
|
const eventKey = getEventKey(e);
|
|
115
127
|
if (!eventKey)
|
|
116
128
|
return;
|
|
117
|
-
const nextPressedMap = { ...
|
|
129
|
+
const nextPressedMap = { ...pressedMapRef.current };
|
|
118
130
|
nextPressedMap[eventKey] = e;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
if (nextPressedMap["meta"]) {
|
|
132
|
+
if (!MODIFIER_KEYS.includes(eventKey)) {
|
|
133
|
+
// Keys pressed while Meta was held might have been released already
|
|
134
|
+
// without us receiving their keyup events, so when the whole pressed combination
|
|
135
|
+
// doesn't match any hotkey - we treat them as released
|
|
136
|
+
const staleKeys = metaModifiedKeysRef.current.filter((key) => key !== eventKey && key in nextPressedMap);
|
|
137
|
+
const pressedId = getHotkeyId(Object.keys(nextPressedMap).join(COMBINATION_DELIMETER));
|
|
138
|
+
if (staleKeys.length && !globalHotkeyStore.hasHandlers(pressedId)) {
|
|
139
|
+
staleKeys.forEach((key) => delete nextPressedMap[key]);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
metaModifiedKeysRef.current = Object.keys(nextPressedMap).filter((key) => !MODIFIER_KEYS.includes(key));
|
|
143
|
+
}
|
|
125
144
|
setPressedMap(nextPressedMap);
|
|
126
145
|
return nextPressedMap;
|
|
127
|
-
}, [
|
|
146
|
+
}, [setPressedMap]);
|
|
128
147
|
const removePressedKey = React.useCallback((e) => {
|
|
129
148
|
if (hooksCountRef.current === 0)
|
|
130
149
|
return;
|
|
131
150
|
const eventKey = getEventKey(e);
|
|
132
151
|
if (!eventKey)
|
|
133
152
|
return;
|
|
134
|
-
const nextPressedMap = { ...
|
|
153
|
+
const nextPressedMap = { ...pressedMapRef.current };
|
|
135
154
|
delete nextPressedMap[eventKey];
|
|
136
|
-
if (eventKey === "meta" || eventKey === "control") {
|
|
137
|
-
delete nextPressedMap["mod"];
|
|
138
|
-
}
|
|
139
155
|
if (eventKey === "meta") {
|
|
140
|
-
|
|
141
|
-
if (!nextPressedMap[key])
|
|
142
|
-
return;
|
|
156
|
+
metaModifiedKeysRef.current.forEach((key) => {
|
|
143
157
|
delete nextPressedMap[key];
|
|
144
158
|
});
|
|
145
|
-
|
|
159
|
+
metaModifiedKeysRef.current = [];
|
|
146
160
|
}
|
|
147
161
|
setPressedMap(nextPressedMap);
|
|
148
|
-
}, [
|
|
149
|
-
const isPressed = (hotkey) => {
|
|
162
|
+
}, [setPressedMap]);
|
|
163
|
+
const isPressed = React.useCallback((hotkey) => {
|
|
164
|
+
const pressedMap = pressedMapRef.current;
|
|
150
165
|
const keys = formatHotkey(hotkey).split(COMBINATION_DELIMETER);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
166
|
+
return keys.every((key) => {
|
|
167
|
+
if (key === "mod")
|
|
168
|
+
return Boolean(pressedMap["meta"] || pressedMap["control"]);
|
|
169
|
+
return Boolean(pressedMap[key]);
|
|
170
|
+
});
|
|
171
|
+
}, []);
|
|
155
172
|
const handleWindowKeyDown = React.useCallback((e) => {
|
|
156
173
|
// Browsers trigger keyboard event without passing e.key when you click on autocomplete
|
|
157
174
|
if (!e.key)
|
|
158
175
|
return;
|
|
159
|
-
const nextPressedMap = addPressedKey(e) ??
|
|
176
|
+
const nextPressedMap = addPressedKey(e) ?? pressedMapRef.current;
|
|
160
177
|
globalHotkeyStore.handleKeyDown(nextPressedMap, e);
|
|
161
|
-
}, [addPressedKey
|
|
178
|
+
}, [addPressedKey]);
|
|
162
179
|
const handleWindowKeyUp = React.useCallback((e) => {
|
|
163
180
|
if (!e.key)
|
|
164
181
|
return;
|
|
@@ -166,14 +183,14 @@ export const SingletonHotkeysProvider = (props) => {
|
|
|
166
183
|
}, [removePressedKey]);
|
|
167
184
|
const handleWindowBlur = React.useCallback(() => {
|
|
168
185
|
setPressedMap({});
|
|
169
|
-
|
|
170
|
-
}, []);
|
|
186
|
+
metaModifiedKeysRef.current = [];
|
|
187
|
+
}, [setPressedMap]);
|
|
171
188
|
const addHotkeys = React.useCallback((hotkeys, ref, options = {}) => {
|
|
172
189
|
hooksCountRef.current += 1;
|
|
173
|
-
globalHotkeyStore.bindHotkeys(hotkeys, ref, options);
|
|
190
|
+
const unbindHotkeys = globalHotkeyStore.bindHotkeys(hotkeys, ref, options);
|
|
174
191
|
return () => {
|
|
175
192
|
hooksCountRef.current -= 1;
|
|
176
|
-
|
|
193
|
+
unbindHotkeys();
|
|
177
194
|
};
|
|
178
195
|
}, []);
|
|
179
196
|
React.useEffect(() => {
|
|
@@ -188,4 +205,13 @@ export const SingletonHotkeysProvider = (props) => {
|
|
|
188
205
|
}, [handleWindowKeyDown, handleWindowKeyUp, handleWindowBlur]);
|
|
189
206
|
return (_jsx(HotkeyContext.Provider, { value: { addHotkeys, isPressed }, children: children }));
|
|
190
207
|
};
|
|
208
|
+
export const SingletonHotkeysProvider = (props) => {
|
|
209
|
+
const { children } = props;
|
|
210
|
+
// Hotkeys are handled globally, so nested providers rely on the root provider
|
|
211
|
+
// instead of attaching their own window event listeners
|
|
212
|
+
const hasParentProvider = Boolean(React.useContext(HotkeyContext).addHotkeys);
|
|
213
|
+
if (hasParentProvider)
|
|
214
|
+
return _jsx(_Fragment, { children: children });
|
|
215
|
+
return _jsx(HotkeysProvider, { children: children });
|
|
216
|
+
};
|
|
191
217
|
export const useSingletonHotkeys = () => React.useContext(HotkeyContext);
|
|
@@ -3,6 +3,16 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import React from "react";
|
|
4
4
|
import { activateKeyboardMode, deactivateKeyboardMode } from "@reshaped/utilities/internal";
|
|
5
5
|
const ESC = "Escape";
|
|
6
|
+
const isEditing = (e) => {
|
|
7
|
+
const el = e.target;
|
|
8
|
+
if (!el?.tagName)
|
|
9
|
+
return false;
|
|
10
|
+
const tagName = el.tagName?.toLowerCase();
|
|
11
|
+
const editable = el.isContentEditable || tagName === "textarea" || tagName === "input";
|
|
12
|
+
if (!editable)
|
|
13
|
+
return false;
|
|
14
|
+
return e.isComposing || e.key.length === 1;
|
|
15
|
+
};
|
|
6
16
|
const SingletonKeyboardModeContext = React.createContext({
|
|
7
17
|
disabledRef: null,
|
|
8
18
|
disable: () => { },
|
|
@@ -34,6 +44,8 @@ export const SingletonKeyboardModeProvider = (props) => {
|
|
|
34
44
|
// Prevent focus ring from appearing when using mouse but closing with esc
|
|
35
45
|
if (e.key === ESC)
|
|
36
46
|
return;
|
|
47
|
+
if (isEditing(e))
|
|
48
|
+
return;
|
|
37
49
|
activate();
|
|
38
50
|
}, [activate]);
|
|
39
51
|
const handleClick = React.useCallback(() => {
|
|
@@ -10,21 +10,19 @@ const useOnClickOutside = (refs, handler, options) => {
|
|
|
10
10
|
* before we checked if it's inside the refs
|
|
11
11
|
*/
|
|
12
12
|
const isMouseDownInsideRef = React.useRef(false);
|
|
13
|
+
const checkEventInsideRefs = (event) => {
|
|
14
|
+
const eventEl = event.composedPath()[0];
|
|
15
|
+
if (!eventEl)
|
|
16
|
+
return false;
|
|
17
|
+
return refs.some((elRef) => !!elRef.current && (elRef.current === eventEl || elRef.current.contains(eventEl)));
|
|
18
|
+
};
|
|
13
19
|
React.useEffect(() => {
|
|
14
20
|
/**
|
|
15
21
|
* Not checking for disabled here since some components can enable the hook
|
|
16
22
|
* after it was clicked
|
|
17
23
|
*/
|
|
18
24
|
const handleMouseDown = (event) => {
|
|
19
|
-
isMouseDownInsideRef.current =
|
|
20
|
-
const clickedEl = event.composedPath()[0];
|
|
21
|
-
refs.forEach((elRef) => {
|
|
22
|
-
if (!elRef.current)
|
|
23
|
-
return;
|
|
24
|
-
if (elRef.current === clickedEl || elRef.current.contains(clickedEl)) {
|
|
25
|
-
isMouseDownInsideRef.current = true;
|
|
26
|
-
}
|
|
27
|
-
});
|
|
25
|
+
isMouseDownInsideRef.current = checkEventInsideRefs(event);
|
|
28
26
|
};
|
|
29
27
|
const handleKeyDown = (event) => {
|
|
30
28
|
if (![keys.ENTER, keys.SPACE].includes(event.key))
|
|
@@ -47,15 +45,25 @@ const useOnClickOutside = (refs, handler, options) => {
|
|
|
47
45
|
if (disabled)
|
|
48
46
|
return;
|
|
49
47
|
const handleClick = (event) => {
|
|
50
|
-
if (
|
|
51
|
-
|
|
48
|
+
if (event.type === "contextmenu") {
|
|
49
|
+
/**
|
|
50
|
+
* Context menu events can be claimed by a handler that opens a menu of its own,
|
|
51
|
+
* which prevents the default browser behavior. Such events open a new flyout
|
|
52
|
+
* instead of dismissing the current one, so they're not outside clicks
|
|
53
|
+
*/
|
|
54
|
+
if (event.defaultPrevented)
|
|
55
|
+
return;
|
|
56
|
+
isMouseDownInsideRef.current = checkEventInsideRefs(event);
|
|
57
|
+
}
|
|
52
58
|
if (isMouseDownInsideRef.current)
|
|
53
59
|
return;
|
|
54
60
|
handlerRef.current?.(event);
|
|
55
61
|
};
|
|
56
62
|
document.addEventListener("click", handleClick);
|
|
63
|
+
document.addEventListener("contextmenu", handleClick);
|
|
57
64
|
return () => {
|
|
58
65
|
document.removeEventListener("click", handleClick);
|
|
66
|
+
document.removeEventListener("contextmenu", handleClick);
|
|
59
67
|
};
|
|
60
68
|
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
|
61
69
|
}, [handlerRef, disabled, ...refs]);
|
package/dist/index.d.ts
CHANGED
|
@@ -90,8 +90,12 @@ export type { ActionableProps, ActionableRef } from "./components/Actionable";
|
|
|
90
90
|
export { default as Actionable } from "./components/Actionable";
|
|
91
91
|
export type { ContainerProps } from "./components/Container";
|
|
92
92
|
export { default as Container } from "./components/Container";
|
|
93
|
+
export type { ContentToggleProps } from "./components/ContentToggle";
|
|
94
|
+
export { default as ContentToggle } from "./components/ContentToggle";
|
|
93
95
|
export type { DismissibleProps } from "./components/Dismissible";
|
|
94
96
|
export { default as Dismissible } from "./components/Dismissible";
|
|
97
|
+
export type { ExpandableProps } from "./components/Expandable";
|
|
98
|
+
export { default as Expandable } from "./components/Expandable";
|
|
95
99
|
export type { FlyoutInstance, FlyoutProps, FlyoutTriggerAttributes } from "./components/Flyout";
|
|
96
100
|
export { default as Flyout } from "./components/Flyout";
|
|
97
101
|
export type { FormControlProps } from "./components/FormControl";
|
|
@@ -106,6 +110,8 @@ export type { HiddenVisuallyProps } from "./components/HiddenVisually";
|
|
|
106
110
|
export { default as HiddenVisually } from "./components/HiddenVisually";
|
|
107
111
|
export type { IconProps } from "./components/Icon";
|
|
108
112
|
export { default as Icon } from "./components/Icon";
|
|
113
|
+
export type { IconToggleProps } from "./components/IconToggle";
|
|
114
|
+
export { default as IconToggle } from "./components/IconToggle";
|
|
109
115
|
export type { ImageProps } from "./components/Image";
|
|
110
116
|
export { default as Image } from "./components/Image";
|
|
111
117
|
export type { OverlayProps } from "./components/Overlay";
|
package/dist/index.js
CHANGED
|
@@ -41,7 +41,9 @@ export { default as Tooltip } from "./components/Tooltip";
|
|
|
41
41
|
export { default as Accordion } from "./components/Accordion";
|
|
42
42
|
export { default as Actionable } from "./components/Actionable";
|
|
43
43
|
export { default as Container } from "./components/Container";
|
|
44
|
+
export { default as ContentToggle } from "./components/ContentToggle";
|
|
44
45
|
export { default as Dismissible } from "./components/Dismissible";
|
|
46
|
+
export { default as Expandable } from "./components/Expandable";
|
|
45
47
|
export { default as Flyout } from "./components/Flyout";
|
|
46
48
|
export { default as FormControl } from "./components/FormControl";
|
|
47
49
|
export { default as Grid } from "./components/Grid";
|
|
@@ -49,6 +51,7 @@ export { default as Hidden } from "./components/Hidden";
|
|
|
49
51
|
export { default as HiddenInput } from "./components/HiddenInput";
|
|
50
52
|
export { default as HiddenVisually } from "./components/HiddenVisually";
|
|
51
53
|
export { default as Icon } from "./components/Icon";
|
|
54
|
+
export { default as IconToggle } from "./components/IconToggle";
|
|
52
55
|
export { default as Image } from "./components/Image";
|
|
53
56
|
export { default as Overlay } from "./components/Overlay";
|
|
54
57
|
export { default as Reshaped } from "./components/Reshaped";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reshaped",
|
|
3
|
-
"version": "4.2.0
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Professionally crafted design system in React and Figma for building products of any scale and complexity",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
"cssnano": "8.0.2",
|
|
81
81
|
"csstype": "3.2.3",
|
|
82
82
|
"postcss-custom-media": "12.0.1",
|
|
83
|
-
"@reshaped/
|
|
84
|
-
"@reshaped/
|
|
83
|
+
"@reshaped/theming": "4.2.0",
|
|
84
|
+
"@reshaped/utilities": "4.2.0"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
87
|
"postcss": "^8",
|