@webority/ui-react 0.53.1 → 0.55.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/components/AppActionIcon.js +1 -1
- package/dist/components/AppAutocomplete.js +1 -1
- package/dist/components/AppAvatar.js +1 -1
- package/dist/components/AppButton.js +1 -1
- package/dist/components/AppButtonGroup.js +1 -0
- package/dist/components/AppCarousel.js +1 -0
- package/dist/components/AppChipGroup.js +1 -0
- package/dist/components/AppCodeBlock.js +1 -0
- package/dist/components/AppCommandPalette.js +1 -1
- package/dist/components/AppCommentThread.js +1 -0
- package/dist/components/AppDataTable.js +1 -1
- package/dist/components/AppDateRangePicker.js +1 -1
- package/dist/components/AppDrawer.js +1 -0
- package/dist/components/AppDropdown.js +1 -1
- package/dist/components/AppEmptyState.js +1 -1
- package/dist/components/AppFilterBar.js +1 -1
- package/dist/components/AppHoverCard.js +1 -0
- package/dist/components/AppInlineEdit.js +1 -0
- package/dist/components/AppInputGroup.js +1 -0
- package/dist/components/AppKbd.js +1 -0
- package/dist/components/AppLightbox.js +1 -0
- package/dist/components/AppMentionInput.js +1 -0
- package/dist/components/AppMenubar.js +1 -0
- package/dist/components/AppMultiSelect.js +1 -1
- package/dist/components/AppNavigationMenu.js +1 -0
- package/dist/components/AppNotificationCenter.js +1 -0
- package/dist/components/AppOnboardingChecklist.js +1 -0
- package/dist/components/AppRating.js +1 -0
- package/dist/components/AppRecordPager.js +1 -0
- package/dist/components/AppRelativeTime.js +1 -0
- package/dist/components/AppResizable.js +1 -0
- package/dist/components/AppResizableHandle.js +1 -0
- package/dist/components/AppResizablePanel.js +1 -0
- package/dist/components/AppRollingNumber.js +1 -0
- package/dist/components/AppSectionCallToAction.js +1 -0
- package/dist/components/AppSectionFaq.js +1 -0
- package/dist/components/AppSectionFeatures.js +1 -0
- package/dist/components/AppSectionHero.js +1 -0
- package/dist/components/AppSectionLogos.js +1 -0
- package/dist/components/AppSectionPricing.js +1 -0
- package/dist/components/AppSectionTestimonials.js +1 -0
- package/dist/components/AppSelect.js +1 -1
- package/dist/components/AppSelectMini.js +1 -1
- package/dist/components/AppShortcutLegend.js +1 -0
- package/dist/components/AppShowMore.js +1 -0
- package/dist/components/AppSplitButton.js +1 -0
- package/dist/components/AppSplitView.js +1 -0
- package/dist/components/AppTableEmptyState.js +1 -1
- package/dist/components/AppTableToolbar.js +1 -1
- package/dist/components/AppTabs.js +1 -1
- package/dist/components/AppTooltip.js +1 -1
- package/dist/components/AppTour.js +1 -1
- package/dist/components/AppTruncate.js +1 -0
- package/dist/components/AppWhatsNew.js +1 -0
- package/dist/components/withTooltip.js +1 -1
- package/dist/lib/emptyIllustration.js +1 -0
- package/dist/lib/sectionShell.js +1 -0
- package/dist/lib/shortcutChip.js +1 -0
- package/dist/lib/useListShortcuts.js +1 -0
- package/dist/types/components/AppActionIcon.d.ts +4 -1
- package/dist/types/components/AppAutocomplete.d.ts +9 -2
- package/dist/types/components/AppButton.d.ts +2 -1
- package/dist/types/components/AppButtonGroup.d.ts +23 -0
- package/dist/types/components/AppCarousel.d.ts +52 -0
- package/dist/types/components/AppChipGroup.d.ts +22 -0
- package/dist/types/components/AppCodeBlock.d.ts +28 -0
- package/dist/types/components/AppCommandPalette.d.ts +44 -2
- package/dist/types/components/AppCommentThread.d.ts +115 -0
- package/dist/types/components/AppDataTable.d.ts +44 -1
- package/dist/types/components/AppDateRangePicker.d.ts +5 -0
- package/dist/types/components/AppDrawer.d.ts +46 -0
- package/dist/types/components/AppDropdown.d.ts +4 -1
- package/dist/types/components/AppEmptyState.d.ts +4 -1
- package/dist/types/components/AppFilterBar.d.ts +9 -1
- package/dist/types/components/AppHoverCard.d.ts +35 -0
- package/dist/types/components/AppInlineEdit.d.ts +57 -0
- package/dist/types/components/AppInputGroup.d.ts +29 -0
- package/dist/types/components/AppKbd.d.ts +15 -0
- package/dist/types/components/AppLightbox.d.ts +40 -0
- package/dist/types/components/AppMentionInput.d.ts +41 -0
- package/dist/types/components/AppMenubar.d.ts +45 -0
- package/dist/types/components/AppMultiSelect.d.ts +4 -1
- package/dist/types/components/AppNavigationMenu.d.ts +41 -0
- package/dist/types/components/AppNotificationCenter.d.ts +81 -0
- package/dist/types/components/AppOnboardingChecklist.d.ts +48 -0
- package/dist/types/components/AppRating.d.ts +48 -0
- package/dist/types/components/AppRecordPager.d.ts +38 -0
- package/dist/types/components/AppRelativeTime.d.ts +18 -0
- package/dist/types/components/AppResizable.d.ts +30 -0
- package/dist/types/components/AppResizableHandle.d.ts +13 -0
- package/dist/types/components/AppResizablePanel.d.ts +20 -0
- package/dist/types/components/AppRollingNumber.d.ts +27 -0
- package/dist/types/components/AppSectionCallToAction.d.ts +24 -0
- package/dist/types/components/AppSectionFaq.d.ts +28 -0
- package/dist/types/components/AppSectionFeatures.d.ts +37 -0
- package/dist/types/components/AppSectionHero.d.ts +32 -0
- package/dist/types/components/AppSectionLogos.d.ts +36 -0
- package/dist/types/components/AppSectionPricing.d.ts +28 -0
- package/dist/types/components/AppSectionTestimonials.d.ts +34 -0
- package/dist/types/components/AppShortcutLegend.d.ts +34 -0
- package/dist/types/components/AppShowMore.d.ts +29 -0
- package/dist/types/components/AppSplitButton.d.ts +53 -0
- package/dist/types/components/AppSplitView.d.ts +85 -0
- package/dist/types/components/AppTableEmptyState.d.ts +4 -1
- package/dist/types/components/AppTableToolbar.d.ts +13 -1
- package/dist/types/components/AppTabs.d.ts +12 -6
- package/dist/types/components/AppTooltip.d.ts +4 -1
- package/dist/types/components/AppTour.d.ts +35 -10
- package/dist/types/components/AppTruncate.d.ts +21 -0
- package/dist/types/components/AppWhatsNew.d.ts +44 -0
- package/dist/types/components/withTooltip.d.ts +1 -1
- package/dist/types/index.d.ts +37 -0
- package/dist/types/lib/emptyIllustration.d.ts +22 -0
- package/dist/types/lib/sectionShell.d.ts +43 -0
- package/dist/types/lib/shortcutChip.d.ts +11 -0
- package/dist/types/lib/useListShortcuts.d.ts +24 -0
- package/dist/ui-react.js +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"./warnUnknownProps.js";import"@webority/ui-elements/elements/tour";import{forwardRef as
|
|
1
|
+
import e from"./warnInvalidValue.js";import t from"./warnUnknownProps.js";import"@webority/ui-elements/elements/tour";import{forwardRef as n,useEffect as r,useLayoutEffect as i,useRef as a}from"react";import{jsx as o}from"react/jsx-runtime";var s=[`image`,`video`],c=[`click`],l=n(function({open:n,onClose:l,tourId:u,steps:d,seenStore:f,onBeforeStep:p,labels:m,endDialog:h=!0,className:g,..._},v){t(`AppTour`,_);for(let t of d)e(`AppTour`,`steps[].mediaType`,t.mediaType,s),e(`AppTour`,`steps[].advanceOn`,t.advanceOn,c);let y=a(null),b=e=>{y.current=e,typeof v==`function`?v(e):v&&(v.current=e)};i(()=>{let e=y.current;e.seenStore=f??null,e.onBeforeStep=p??null}),i(()=>{let e=y.current;n?e.setAttribute(`open`,``):e.removeAttribute(`open`)},[n]);let x=a(l);return x.current=l,r(()=>{let e=y.current,t=e=>{let{reason:t,index:n,position:r,total:i}=e.detail;x.current?.(t,{index:n,position:r,total:i})};return e.addEventListener(`wui-tour:close`,t),()=>e.removeEventListener(`wui-tour:close`,t)},[]),o(`wui-tour`,{ref:b,"tour-id":u,"back-label":m?.back,"next-label":m?.next,"skip-label":m?.skip,"done-label":m?.done,"progress-label":m?.progress,"advance-label":m?.advance,"media-pause-label":m?.mediaPause,"media-play-label":m?.mediaPlay,"end-title":m?.endTitle,"end-message":m?.endMessage,"end-button":m?.endButton,"end-dialog":h===!1?`false`:void 0,class:g||void 0,..._,children:d.map(e=>o(`wui-tour-step`,{target:e.target,title:e.title,media:e.media,"media-alt":e.mediaAlt,"media-poster":e.mediaPoster,"media-type":e.mediaType,"advance-on":e.advanceOn,"action-label":e.actionLabel,children:e.description},`${e.target}|${e.description}`))})});export{l as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"./warnUnknownProps.js";import{jsx as t}from"react/jsx-runtime";import"@webority/ui-elements/elements/truncate";function n({children:n,lines:r=1,width:i,style:a,className:o=``,...s}){e(`AppTruncate`,s);let c=Number.isInteger(r)&&r>1,l={...c?{"--wui-truncate-lines":r}:null,...i?{"--wui-truncate-width":i}:null,...a};return t(`wui-truncate`,{class:[`wui-truncate`,c&&`wui-truncate-multi`,o].filter(Boolean).join(` `),style:Object.keys(l).length?l:void 0,...s,children:t(`span`,{className:`wui-truncate-text`,children:n})})}export{n as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"./warnUnknownProps.js";import t from"./AppIcon.js";import{formatDate as n}from"@webority/ui-elements/helpers";import{useEffect as r,useRef as i}from"react";import{jsx as a,jsxs as o}from"react/jsx-runtime";import"@webority/ui-elements/elements/whats-new";function s({entries:s=[],storageKey:c,label:l=`What's new`,unreadLabel:u=`unread`,emptyText:d=`Nothing new yet`,onRead:f,className:p=``,...m}){e(`AppWhatsNew`,m);let h=i(null),g=i(f);return g.current=f,r(()=>{let e=h.current,t=e=>g.current?.(e.detail.through);return e.addEventListener(`wui-whats-new-read`,t),()=>e.removeEventListener(`wui-whats-new-read`,t)},[]),o(`wui-whats-new`,{ref:h,class:[`wui-whats-new`,p].filter(Boolean).join(` `),"storage-key":c||void 0,...m,children:[o(`button`,{type:`button`,className:`u-action wui-whats-new-trigger`,"aria-haspopup":`dialog`,children:[a(t,{name:`gift`,size:20}),a(`span`,{className:`wui-whats-new-name`,children:l}),a(`span`,{className:`wui-whats-new-unread`,children:` ${u}`}),a(`span`,{className:`wui-whats-new-dot`,"aria-hidden":`true`})]}),o(`div`,{className:`wui-whats-new-panel`,role:`dialog`,"aria-label":l,tabIndex:-1,children:[a(`h2`,{className:`wui-whats-new-title`,children:l}),s.length>0?a(`ol`,{className:`wui-whats-new-list`,children:s.map((e,t)=>o(`li`,{className:`wui-whats-new-entry`,children:[a(`time`,{className:`wui-whats-new-date`,dateTime:e.date,children:n(e.date)}),a(`h3`,{className:`wui-whats-new-entry-title`,children:e.title}),e.body&&a(`p`,{className:`wui-whats-new-body`,children:e.body}),e.imageSrc&&a(`img`,{className:`wui-whats-new-image`,src:e.imageSrc,alt:e.imageAlt??``,loading:`lazy`}),e.href&&a(`a`,{className:`wui-whats-new-link`,href:e.href,children:e.linkLabel||`Learn more`})]},e.id??`${e.date}-${t}`))}):a(`p`,{className:`wui-whats-new-empty`,children:d})]})]})}export{s as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"./AppTooltip.js";import{jsx as t}from"react/jsx-runtime";function n(n,r,i){return r==null||r===``?n:t(e,{content:r,placement:i||`auto`,children:n})}export{n as default};
|
|
1
|
+
import e from"./AppTooltip.js";import{jsx as t}from"react/jsx-runtime";function n(n,r,i,a){return r==null||r===``?n:t(e,{content:r,placement:i||`auto`,shortcut:a,children:n})}export{n as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e}from"react/jsx-runtime";var t={"no-results":`<ellipse class="wui-ill-mute" cx="80" cy="104" rx="44" ry="6"/><rect class="wui-ill-card" x="30" y="16" width="64" height="80" rx="8"/><rect class="wui-ill-mute" x="40" y="28" width="30" height="5" rx="2.5"/><rect class="wui-ill-mute" x="40" y="40" width="44" height="5" rx="2.5"/><rect class="wui-ill-mute" x="40" y="52" width="36" height="5" rx="2.5"/><circle class="wui-ill-soft" cx="96" cy="66" r="22"/><circle class="wui-ill-accent-line" cx="96" cy="66" r="22"/><path class="wui-ill-accent-line wui-ill-thick" d="M112 82l14 14"/><path class="wui-ill-accent-line" d="M89 59l14 14M103 59l-14 14"/>`,"no-data":`<ellipse class="wui-ill-mute" cx="80" cy="104" rx="44" ry="6"/><path class="wui-ill-ink" d="M30 20v76h100"/><rect class="wui-ill-dash" x="44" y="62" width="16" height="34" rx="3"/><rect class="wui-ill-dash" x="70" y="44" width="16" height="52" rx="3"/><rect class="wui-ill-dash" x="96" y="28" width="16" height="68" rx="3"/><circle class="wui-ill-accent" cx="122" cy="26" r="5"/>`,"empty-inbox":`<ellipse class="wui-ill-mute" cx="80" cy="104" rx="44" ry="6"/><circle class="wui-ill-soft" cx="80" cy="24" r="14"/><path class="wui-ill-accent-line" d="M73 24l5 5 9-10"/><path class="wui-ill-card" d="M32 66l11-26a6 6 0 0 1 5.5-3.6h63a6 6 0 0 1 5.5 3.6L128 66v22a8 8 0 0 1-8 8H40a8 8 0 0 1-8-8z"/><path class="wui-ill-ink" d="M32 66h30a6 6 0 0 1 6 6 12 12 0 0 0 24 0 6 6 0 0 1 6-6h30"/>`,"no-notifications":`<ellipse class="wui-ill-mute" cx="80" cy="104" rx="44" ry="6"/><path class="wui-ill-ink" d="M80 22v-6"/><path class="wui-ill-card" d="M80 22c-14 0-24 10-24 24v14l-8 12h64l-8-12V46c0-14-10-24-24-24z"/><circle class="wui-ill-accent" cx="80" cy="84" r="6"/><path class="wui-ill-ink" d="M112 30h10l-10 12h10M126 16h7l-7 8h7"/>`,"no-files":`<ellipse class="wui-ill-mute" cx="80" cy="104" rx="44" ry="6"/><path class="wui-ill-soft" d="M28 38a6 6 0 0 1 6-6h24l9 10h59a6 6 0 0 1 6 6v36a8 8 0 0 1-8 8H36a8 8 0 0 1-8-8z"/><path class="wui-ill-ink" d="M28 38a6 6 0 0 1 6-6h24l9 10h59a6 6 0 0 1 6 6v36a8 8 0 0 1-8 8H36a8 8 0 0 1-8-8z"/><path class="wui-ill-card" d="M28 58a6 6 0 0 1 6-6h92a6 6 0 0 1 6 6v28a8 8 0 0 1-8 8H36a8 8 0 0 1-8-8z"/><path class="wui-ill-accent-line" d="M80 66v16M72 74h16"/>`,"no-access":`<ellipse class="wui-ill-mute" cx="80" cy="104" rx="44" ry="6"/><path class="wui-ill-ink" d="M62 54V44a18 18 0 0 1 36 0v10"/><rect class="wui-ill-card" x="52" y="54" width="56" height="42" rx="8"/><circle class="wui-ill-accent" cx="80" cy="71" r="5"/><path class="wui-ill-accent-line" d="M80 76v8"/>`,offline:`<ellipse class="wui-ill-mute" cx="80" cy="104" rx="44" ry="6"/><path class="wui-ill-card" d="M54 88a15 15 0 0 1-1.5-29.9 24 24 0 0 1 46.3-4.6A17 17 0 0 1 108 88z"/><path class="wui-ill-accent-line wui-ill-thick" d="M46 36l72 60"/>`,error:`<ellipse class="wui-ill-mute" cx="80" cy="104" rx="44" ry="6"/><rect class="wui-ill-card" x="44" y="16" width="72" height="82" rx="8"/><rect class="wui-ill-mute" x="56" y="26" width="30" height="5" rx="2.5"/><circle class="wui-ill-danger" cx="80" cy="60" r="20"/><path class="wui-ill-danger-line" d="M80 50v12"/><circle class="wui-ill-danger-fill" cx="80" cy="70" r="2.5"/><rect class="wui-ill-mute" x="62" y="86" width="36" height="5" rx="2.5"/>`},n=Object.keys(t);function r({name:n,className:r}){let i=n&&Object.hasOwn(t,n)?t[n]:void 0;return i?e(`svg`,{className:r?`wui-illustration ${r}`:`wui-illustration`,"data-illustration":n,viewBox:`0 0 160 120`,fill:`none`,"aria-hidden":`true`,focusable:`false`,dangerouslySetInnerHTML:{__html:i}}):null}export{t as ILLUSTRATION_BODIES,n as ILLUSTRATION_NAMES,r as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";var n=[`h1`,`h2`,`h3`,`h4`,`h5`,`h6`],r=[`start`,`center`],i=[`default`,`muted`];function a(e,t){return n.includes(e)?e:t}function o(e){return n[Math.min(n.indexOf(e)+1,5)]}function s({className:t,src:n,alt:r,width:i,height:a}){return e(`img`,{className:t,src:n,alt:r,width:i,height:a,loading:`lazy`,decoding:`async`})}function c({component:n,kind:r,title:i,as:a,eyebrow:o,subtitle:s,align:c,variant:l,actions:u,extraClass:d,className:f,rest:p,children:m}){if(i==null||i===``)throw Error(`${n} needs a title: every section opens with its heading.`);let h=a,g=p.id?`${p.id}-title`:void 0;return e(`section`,{className:[`wui-section`,`wui-section-${r}`,c===`center`?`wui-section-center`:``,l===`muted`?`wui-section-muted`:``,d,f].filter(Boolean).join(` `),"aria-labelledby":g,...p,children:t(`div`,{className:`wui-section-inner`,children:[t(`div`,{className:`wui-section-head`,children:[o!=null&&o!==``&&e(`p`,{className:`wui-section-eyebrow`,children:o}),e(h,{className:`wui-section-title`,id:g,children:i}),s!=null&&s!==``&&e(`p`,{className:`wui-section-subtitle`,children:s}),u!=null&&u!==!1&&e(`div`,{className:`wui-section-actions`,children:u})]}),m]})})}export{r as SECTION_ALIGNS,n as SECTION_HEADINGS,i as SECTION_VARIANTS,s as SectionImage,c as default,o as itemHeading,a as sectionHeading};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ariaKeyShortcuts as e,shortcutKey as t}from"@webority/ui-elements/helpers";import{jsx as n}from"react/jsx-runtime";function r(e,{inTooltip:r=!1}={}){if(e==null||String(e).trim()===``)return null;let i=t(e);return r?n(`span`,{className:`wui-kbd`,children:i}):n(`kbd`,{className:`wui-kbd`,"aria-hidden":`true`,children:i})}function i(n){if(!(n==null||String(n).trim()===``))return e(t(n))}export{i as shortcutAria,r as shortcutChip};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{SHORTCUT_SCOPE_ATTRIBUTE as e,runShortcut as t}from"@webority/ui-elements/helpers";import{useEffect as n,useRef as r}from"react";function i(i,{enabled:a=!0,scope:o}={}){let s=r(i);n(()=>{s.current=i}),n(()=>{if(!a)return;let n=o?.current;n&&!n.hasAttribute(e)&&n.setAttribute(e,``);let r=e=>t(e,s.current,o?.current??null);return document.addEventListener(`keydown`,r),()=>document.removeEventListener(`keydown`,r)},[a,o])}export{i as useListShortcuts};
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
* @param {'auto'|'top'|'bottom'|'start'|'end'} [props.tooltipPlacement='auto'] which side the
|
|
18
18
|
* tooltip prefers. `auto` (default) lets Popper pick the side with the most room; a named side
|
|
19
19
|
* is preferred but still flips to stay in view. Powered by `AppTooltip`, so it never clips.
|
|
20
|
+
* @param {string} [props.shortcut] the key that runs this action ("J", "E", "/"), drawn as a key chip in the tooltip
|
|
21
|
+
* after the label. Sets aria-keyshortcuts; the page binds the key itself (useListShortcuts). Needs a `label`, which supplies the tooltip.
|
|
20
22
|
* @param {boolean} [props.danger] destructive tint
|
|
21
23
|
* @param {boolean} [props.disabled]
|
|
22
24
|
* @param {number} [props.size=20] glyph size in px; the disc (and its hover tint) scales with it, keeping a constant 8px ring
|
|
@@ -28,11 +30,12 @@
|
|
|
28
30
|
* wrapper must use `forwardRef` (the tooltip still opens without it, but may be mispositioned).
|
|
29
31
|
* @param {string} [props.href] sets an anchor without needing `as`.
|
|
30
32
|
*/
|
|
31
|
-
export default function AppActionIcon({ icon, iconVariant, label, tooltipPlacement, danger, disabled, size, onClick, className, as, href, ...rest }: {
|
|
33
|
+
export default function AppActionIcon({ icon, iconVariant, label, tooltipPlacement, shortcut, danger, disabled, size, onClick, className, as, href, ...rest }: {
|
|
32
34
|
icon: string | import('react').ReactNode;
|
|
33
35
|
iconVariant?: 'linear' | 'outline' | 'bold' | 'bulk' | 'broken' | 'twotone';
|
|
34
36
|
label: string;
|
|
35
37
|
tooltipPlacement?: 'auto' | 'top' | 'bottom' | 'start' | 'end';
|
|
38
|
+
shortcut?: string;
|
|
36
39
|
danger?: boolean;
|
|
37
40
|
disabled?: boolean;
|
|
38
41
|
size?: number;
|
|
@@ -6,18 +6,25 @@ import "@webority/ui-elements/elements/autocomplete";
|
|
|
6
6
|
* - **static** — pass `options` (`[{ value, label }]`); filtering is client-side.
|
|
7
7
|
* - **remote** — pass an async `loadOptions(query) => Promise<options>`; the field
|
|
8
8
|
* debounces typing, shows a spinner while your promise is in flight, then lists the
|
|
9
|
-
* results. You own the fetch; the component owns the UX.
|
|
9
|
+
* results. You own the fetch; the component owns the UX. `options` given alongside it
|
|
10
|
+
* are the list shown until the first load result arrives, which replaces them.
|
|
10
11
|
*
|
|
11
12
|
* @param {object} props
|
|
12
13
|
* @param {string} [props.value] Selected option value.
|
|
13
14
|
* @param {(value: string, meta?: { isCustom: boolean }) => void} [props.onChange] The second
|
|
14
15
|
* argument reports whether the commit was a freeform entry (`allowCustom`) rather than a
|
|
15
16
|
* listed option — existing callers reading only the first argument are unaffected.
|
|
16
|
-
* @param {{value: string, label:
|
|
17
|
+
* @param {Array<{ value: string, label: import('react').ReactNode }>} [props.options] Static options,
|
|
18
|
+
* or with `loadOptions` the initial list: shown before any load result arrives (and resolving a
|
|
19
|
+
* pre-filled value's label), then replaced by the first result; later changes are ignored.
|
|
20
|
+
* A label may be a node (`<>CO<sub>2</sub></>`): it renders as static markup in the menu, the
|
|
21
|
+
* input shows its text once chosen, and filtering and the option's accessible name use that
|
|
22
|
+
* text. Remote results from `loadOptions` take string labels only.
|
|
17
23
|
* @param {(query: string, opts?: { signal?: AbortSignal }) => Promise<{value: string, label: string}[]>} [props.loadOptions]
|
|
18
24
|
* Remote loader; receives an AbortSignal for the superseded request (optional to use).
|
|
19
25
|
* @param {string} [props.placeholder]
|
|
20
26
|
* @param {number} [props.minChars] Min chars before a remote search fires (default 1 in remote mode).
|
|
27
|
+
* 0 is allowed: opening the field with an empty box calls `loadOptions("")` for the first page.
|
|
21
28
|
* @param {number} [props.debounce] Debounce ms for remote search (default 250).
|
|
22
29
|
* @param {boolean} [props.disabled]
|
|
23
30
|
* @param {'sm'|'lg'} [props.size] Control size around the default.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export default function AppButton({ children, variant, size, type, loading, disabled, block, leftIcon, rightIcon, href, static: isStatic, tooltip, tooltipPlacement, className, ...rest }: {
|
|
1
|
+
export default function AppButton({ children, variant, size, type, loading, disabled, block, leftIcon, rightIcon, href, static: isStatic, tooltip, tooltipPlacement, shortcut, className, ...rest }: {
|
|
2
2
|
[x: string]: any;
|
|
3
3
|
block?: boolean;
|
|
4
4
|
children: any;
|
|
@@ -8,6 +8,7 @@ export default function AppButton({ children, variant, size, type, loading, disa
|
|
|
8
8
|
leftIcon?: any;
|
|
9
9
|
loading?: boolean;
|
|
10
10
|
rightIcon?: any;
|
|
11
|
+
shortcut: any;
|
|
11
12
|
size?: string;
|
|
12
13
|
static?: boolean;
|
|
13
14
|
tooltip: any;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Related buttons joined into one control: a view switch, a bulk-action row, a text-style set
|
|
3
|
+
* ("Bold", "Italic"). The buttons touch, share one outline and keep their own variants and
|
|
4
|
+
* handlers; give every button in the group the same `variant` and leave `size` to the group.
|
|
5
|
+
* The group is announced by `label`; each button is still its own tab stop (this is a set of
|
|
6
|
+
* actions, not a single-choice control; for one choice of several use `AppSegmented`).
|
|
7
|
+
*
|
|
8
|
+
* @param {object} props
|
|
9
|
+
* @param {string} props.label Accessible name for the group ("Text style").
|
|
10
|
+
* @param {import('react').ReactNode} props.children `AppButton`s (or button-styled links).
|
|
11
|
+
* @param {'sm'|'md'|'lg'} [props.size='md'] One size for every button in the group.
|
|
12
|
+
* @param {boolean} [props.vertical=false] Stack the buttons top to bottom.
|
|
13
|
+
* @param {boolean} [props.fullWidth=false] Fill the container, the buttons sharing the row equally.
|
|
14
|
+
* @param {string} [props.className]
|
|
15
|
+
*/
|
|
16
|
+
export default function AppButtonGroup({ label, children, size, vertical, fullWidth, className, ...rest }: {
|
|
17
|
+
label: string;
|
|
18
|
+
children: import('react').ReactNode;
|
|
19
|
+
size?: 'sm' | 'md' | 'lg';
|
|
20
|
+
vertical?: boolean;
|
|
21
|
+
fullWidth?: boolean;
|
|
22
|
+
className?: string;
|
|
23
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import "@webority/ui-elements/elements/carousel";
|
|
2
|
+
/**
|
|
3
|
+
* A row of slides you can step through, drag or swipe: previous and next buttons, a dot per page, and
|
|
4
|
+
* optional auto-advance that can always be stopped. Each child is one slide.
|
|
5
|
+
*
|
|
6
|
+
* With `autoplay` it advances every that many milliseconds and shows a visible Pause / Play button
|
|
7
|
+
* before the slides. It holds while the pointer is over it or focus is inside, while the tab is hidden,
|
|
8
|
+
* and not at all when the user prefers reduced motion (the button is hidden then). It wraps to the
|
|
9
|
+
* first slide; the buttons wrap only with `loop`. The slides are named "2 of 5", and the page that
|
|
10
|
+
* comes into view is announced politely when the user, not the autoplay, moved it. The focused slide
|
|
11
|
+
* row also takes Left, Right, Home and End.
|
|
12
|
+
*
|
|
13
|
+
* `perView` shows several slides at once (its `Md` and `Lg` forms apply from those breakpoints), and
|
|
14
|
+
* the dots then stand for pages of slides. Wraps the shared `<wui-carousel>` element, which owns the
|
|
15
|
+
* stepping and the autoplay; the Razor `<app-carousel>` renders the same markup.
|
|
16
|
+
*
|
|
17
|
+
* @param {object} props
|
|
18
|
+
* @param {string} props.label What the slides are ("Customer stories"): the carousel's accessible name.
|
|
19
|
+
* @param {number} [props.autoplay] Milliseconds between automatic steps (5000 is typical). Omit for none.
|
|
20
|
+
* @param {boolean} [props.loop=false] The previous and next buttons wrap around at the ends.
|
|
21
|
+
* @param {number} [props.perView=1] Slides in view on a phone.
|
|
22
|
+
* @param {number} [props.perViewMd] Slides in view from the md breakpoint. Defaults to `perView`.
|
|
23
|
+
* @param {number} [props.perViewLg] Slides in view from the lg breakpoint. Defaults to `perViewMd`.
|
|
24
|
+
* @param {boolean} [props.arrows=true] Show the previous and next buttons.
|
|
25
|
+
* @param {boolean} [props.dots=true] Show the page dots.
|
|
26
|
+
* @param {string} [props.previousLabel="Previous slide"] The previous button's name.
|
|
27
|
+
* @param {string} [props.nextLabel="Next slide"] The next button's name.
|
|
28
|
+
* @param {string} [props.dotLabel="Go to slide"] The words before the slide number in each dot's name.
|
|
29
|
+
* @param {string} [props.pauseLabel="Pause"] The pause button's text and name while playing.
|
|
30
|
+
* @param {string} [props.playLabel="Play"] The pause button's text and name while paused.
|
|
31
|
+
* @param {string} [props.className]
|
|
32
|
+
* @param {import('react').CSSProperties} [props.style] Merged after the per-view custom properties.
|
|
33
|
+
* @param {import('react').ReactNode} props.children The slides.
|
|
34
|
+
*/
|
|
35
|
+
export default function AppCarousel({ label, autoplay, loop, perView, perViewMd, perViewLg, arrows, dots, previousLabel, nextLabel, dotLabel, pauseLabel, playLabel, className, children, style, ...rest }: {
|
|
36
|
+
label: string;
|
|
37
|
+
autoplay?: number;
|
|
38
|
+
loop?: boolean;
|
|
39
|
+
perView?: number;
|
|
40
|
+
perViewMd?: number;
|
|
41
|
+
perViewLg?: number;
|
|
42
|
+
arrows?: boolean;
|
|
43
|
+
dots?: boolean;
|
|
44
|
+
previousLabel?: string;
|
|
45
|
+
nextLabel?: string;
|
|
46
|
+
dotLabel?: string;
|
|
47
|
+
pauseLabel?: string;
|
|
48
|
+
playLabel?: string;
|
|
49
|
+
className?: string;
|
|
50
|
+
style?: import('react').CSSProperties;
|
|
51
|
+
children: import('react').ReactNode;
|
|
52
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import "@webority/ui-elements/elements/overflow";
|
|
2
|
+
/**
|
|
3
|
+
* A row of chips (`AppChip`, `AppChoiceChip`) that either wraps onto more lines or, with
|
|
4
|
+
* `overflow="menu"`, keeps one line and moves the chips that do not fit into a More menu
|
|
5
|
+
* (`<wui-overflow>`, which Razor `<app-chip-group>` renders too). Choosing a chip in the menu
|
|
6
|
+
* clicks that chip's own control, so a clickable `AppChip` runs its `onClick` and an
|
|
7
|
+
* `AppChoiceChip` toggles. A chip with no control (static or only removable) is listed greyed out.
|
|
8
|
+
*
|
|
9
|
+
* @param {object} props
|
|
10
|
+
* @param {import('react').ReactNode} props.children The chips.
|
|
11
|
+
* @param {"wrap"|"menu"} [props.overflow="wrap"] `wrap` lets the chips wrap; `menu` moves the extras into a More menu.
|
|
12
|
+
* @param {string} [props.moreLabel="More"] The More button's text when `overflow="menu"`.
|
|
13
|
+
* @param {string} [props.label] Accessible name for the group.
|
|
14
|
+
* @param {string} [props.className]
|
|
15
|
+
*/
|
|
16
|
+
export default function AppChipGroup({ children, overflow, moreLabel, label, className, ...rest }: {
|
|
17
|
+
children: import('react').ReactNode;
|
|
18
|
+
overflow?: "wrap" | "menu";
|
|
19
|
+
moreLabel?: string;
|
|
20
|
+
label?: string;
|
|
21
|
+
className?: string;
|
|
22
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import "@webority/ui-elements/elements/code-block";
|
|
2
|
+
/**
|
|
3
|
+
* Source code with syntax colours (light and dark), a Copy button with a confirmation, optional
|
|
4
|
+
* line numbers and optional wrapping, for docs pages, API keys, webhook payloads and request
|
|
5
|
+
* examples. The colouring is a small built-in tokenizer in `<wui-code-block>`, which Razor
|
|
6
|
+
* `<app-code-block>` renders too; the source is only ever drawn as text, never as HTML. Source
|
|
7
|
+
* beyond 100,000 characters is shown uncoloured. Not an editor: it shows code, it does not edit it.
|
|
8
|
+
*
|
|
9
|
+
* @param {object} props
|
|
10
|
+
* @param {string} props.code The source text. A single trailing newline is dropped.
|
|
11
|
+
* @param {"text"|"json"|"js"|"cs"|"sql"|"bash"|"http"|"html"|"css"} [props.language="text"] What to colour; `text` shows it as written.
|
|
12
|
+
* @param {boolean} [props.lineNumbers=false] Number the lines. The numbers are not copied or selected.
|
|
13
|
+
* @param {boolean} [props.wrap=false] Wrap long lines instead of scrolling sideways.
|
|
14
|
+
* @param {string} [props.label] The header title ("webhook.json") and the code region's accessible name. Without it the header names the language.
|
|
15
|
+
* @param {string} [props.copyLabel="Copy"] The copy button's label.
|
|
16
|
+
* @param {string} [props.copiedLabel="Copied"] The copy button's label for two seconds after a copy.
|
|
17
|
+
* @param {string} [props.className]
|
|
18
|
+
*/
|
|
19
|
+
export default function AppCodeBlock({ code, language, lineNumbers, wrap, label, copyLabel, copiedLabel, className, ...rest }: {
|
|
20
|
+
code: string;
|
|
21
|
+
language?: "text" | "json" | "js" | "cs" | "sql" | "bash" | "http" | "html" | "css";
|
|
22
|
+
lineNumbers?: boolean;
|
|
23
|
+
wrap?: boolean;
|
|
24
|
+
label?: string;
|
|
25
|
+
copyLabel?: string;
|
|
26
|
+
copiedLabel?: string;
|
|
27
|
+
className?: string;
|
|
28
|
+
}): import("react").JSX.Element;
|
|
@@ -12,6 +12,15 @@ import "@webority/ui-elements/elements/command-palette";
|
|
|
12
12
|
* You own the search: `query` is controlled, and `groups` is whatever your search returned
|
|
13
13
|
* for it. The palette does not filter. Selecting a result calls its `onSelect`, then `onClose`.
|
|
14
14
|
*
|
|
15
|
+
* Nested pages are controlled the same way. An item with a `page` opens it instead of acting:
|
|
16
|
+
* the palette calls `onPathChange` with the new path and `onQueryChange("")`, and you pass the
|
|
17
|
+
* groups of the page `path` names. A Back button and a breadcrumb appear while the path is not
|
|
18
|
+
* empty; Backspace in an empty search goes back. Reset `path` yourself when you close the palette.
|
|
19
|
+
*
|
|
20
|
+
* With `recentsKey` the palette remembers what was chosen on this device and lists it first, under
|
|
21
|
+
* "Recent", while the search is empty on the first page. Items are remembered by group key and
|
|
22
|
+
* item key, so keep both stable, and only items present in the root `groups` are listed again.
|
|
23
|
+
*
|
|
15
24
|
* @param {object} props
|
|
16
25
|
* @param {boolean} props.open
|
|
17
26
|
* @param {() => void} props.onClose Called on Escape, a backdrop click, and after a selection.
|
|
@@ -21,13 +30,28 @@ import "@webority/ui-elements/elements/command-palette";
|
|
|
21
30
|
* @param {{ key: string, label: import('react').ReactNode, items: { key: string,
|
|
22
31
|
* label: import('react').ReactNode, description?: import('react').ReactNode,
|
|
23
32
|
* icon?: string | import('react').ReactNode, meta?: import('react').ReactNode,
|
|
24
|
-
* disabled?: boolean, ariaLabel?: string,
|
|
33
|
+
* disabled?: boolean, ariaLabel?: string, shortcut?: string,
|
|
34
|
+
* page?: { key: string, label: string }, onSelect?: () => void }[] }[]} [props.groups=[]]
|
|
25
35
|
* Results, rendered in order under their group headings. Keys must be unique within their
|
|
26
36
|
* group; groups with no items are left out. `icon` is a library icon name or a node; `meta` is
|
|
27
37
|
* short trailing text or a node. A `disabled` item is listed but cannot be chosen: the arrow
|
|
28
38
|
* keys skip it. `ariaLabel` is the option's accessible name, by default a string `label`, so a
|
|
29
39
|
* screen reader reads the name whole rather than in the pieces the search emphasis splits it
|
|
30
40
|
* into; give it for a label passed as a node. The description and meta describe the option.
|
|
41
|
+
* `shortcut` is the key that runs the item elsewhere ("N", "Ctrl K"), drawn as a key chip at
|
|
42
|
+
* the end of the row; it is a hint, your page binds the key. `page` makes the item open a
|
|
43
|
+
* nested page ({ key, label }, the label shows in the breadcrumb) instead of calling `onSelect`.
|
|
44
|
+
* @param {{ key: string, label: string }[]} [props.path=[]] The open nested pages, outermost first
|
|
45
|
+
* (controlled). Empty shows the first page.
|
|
46
|
+
* @param {(path: { key: string, label: string }[]) => void} [props.onPathChange] Called with the
|
|
47
|
+
* new path when the user opens a page, presses Back, picks a breadcrumb entry, or presses
|
|
48
|
+
* Backspace in an empty search. The search is cleared with it.
|
|
49
|
+
* @param {string} [props.rootLabel='All'] Breadcrumb text for the first page.
|
|
50
|
+
* @param {string} [props.backLabel='Back'] Accessible name of the Back button.
|
|
51
|
+
* @param {string} [props.recentsKey] localStorage key to remember chosen items under; omit for no
|
|
52
|
+
* recents. Make it per user, for example from the user's public id.
|
|
53
|
+
* @param {number} [props.recentsLimit=5] How many recent items to keep (at most 20).
|
|
54
|
+
* @param {string} [props.recentsLabel='Recent'] Heading of the recent items.
|
|
31
55
|
* @param {boolean} [props.loading=false] Shows the library spinner in the input.
|
|
32
56
|
* @param {import('react').ReactNode} [props.emptyText='No results'] Shown when the query is
|
|
33
57
|
* not blank, nothing is loading, and no group has items.
|
|
@@ -38,7 +62,7 @@ import "@webority/ui-elements/elements/command-palette";
|
|
|
38
62
|
* @param {string} [props.id] Seeds the result and heading ids; defaults to a generated id.
|
|
39
63
|
* @param {string} [props.className] Extra classes on the dialog card.
|
|
40
64
|
*/
|
|
41
|
-
export default function AppCommandPalette({ open, onClose, query, onQueryChange, placeholder, groups, loading, emptyText, footer, ariaLabel, highlight, id, className, ...rest }: {
|
|
65
|
+
export default function AppCommandPalette({ open, onClose, query, onQueryChange, placeholder, groups, path, onPathChange, rootLabel, backLabel, recentsKey, recentsLimit, recentsLabel, loading, emptyText, footer, ariaLabel, highlight, id, className, ...rest }: {
|
|
42
66
|
open: boolean;
|
|
43
67
|
onClose: () => void;
|
|
44
68
|
query?: string;
|
|
@@ -55,9 +79,27 @@ export default function AppCommandPalette({ open, onClose, query, onQueryChange,
|
|
|
55
79
|
meta?: import('react').ReactNode;
|
|
56
80
|
disabled?: boolean;
|
|
57
81
|
ariaLabel?: string;
|
|
82
|
+
shortcut?: string;
|
|
83
|
+
page?: {
|
|
84
|
+
key: string;
|
|
85
|
+
label: string;
|
|
86
|
+
};
|
|
58
87
|
onSelect?: () => void;
|
|
59
88
|
}[];
|
|
60
89
|
}[];
|
|
90
|
+
path?: {
|
|
91
|
+
key: string;
|
|
92
|
+
label: string;
|
|
93
|
+
}[];
|
|
94
|
+
onPathChange?: (path: {
|
|
95
|
+
key: string;
|
|
96
|
+
label: string;
|
|
97
|
+
}[]) => void;
|
|
98
|
+
rootLabel?: string;
|
|
99
|
+
backLabel?: string;
|
|
100
|
+
recentsKey?: string;
|
|
101
|
+
recentsLimit?: number;
|
|
102
|
+
recentsLabel?: string;
|
|
61
103
|
loading?: boolean;
|
|
62
104
|
emptyText?: import('react').ReactNode;
|
|
63
105
|
footer?: import('react').ReactNode;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
export type CommentThreadItem = {
|
|
2
|
+
/**
|
|
3
|
+
* The comment's public id.
|
|
4
|
+
*/
|
|
5
|
+
id: string;
|
|
6
|
+
/**
|
|
7
|
+
* Who wrote it; `src` is a photo URL.
|
|
8
|
+
*/
|
|
9
|
+
author: {
|
|
10
|
+
name: string;
|
|
11
|
+
src?: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* When it was written: an ISO instant with its zone, epoch ms or a Date. Shown in IST.
|
|
15
|
+
*/
|
|
16
|
+
at: string | number | Date;
|
|
17
|
+
/**
|
|
18
|
+
* The stored body, with mentions as `@[Label](id)`.
|
|
19
|
+
*/
|
|
20
|
+
value?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Shows "Edited" beside the time.
|
|
23
|
+
*/
|
|
24
|
+
edited?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Shows "This comment was deleted." in place of the body; replies stay.
|
|
27
|
+
*/
|
|
28
|
+
deleted?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* This person may edit it.
|
|
31
|
+
*/
|
|
32
|
+
canEdit?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* This person may delete it.
|
|
35
|
+
*/
|
|
36
|
+
canDelete?: boolean;
|
|
37
|
+
reactions?: {
|
|
38
|
+
emoji: string;
|
|
39
|
+
count: number;
|
|
40
|
+
mine?: boolean;
|
|
41
|
+
}[];
|
|
42
|
+
/**
|
|
43
|
+
* Replies, oldest first. Replies to a reply are not nested.
|
|
44
|
+
*/
|
|
45
|
+
replies?: CommentThreadItem[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* A discussion: comments with their author, time in IST, replies one level deep, reactions and
|
|
49
|
+
* mentions. People reply, edit and delete in place (Delete asks first), react from a small panel,
|
|
50
|
+
* and write with "@" to mention someone (see `AppMentionInput`). Ctrl or Cmd+Enter sends a box,
|
|
51
|
+
* Escape closes it and returns focus. Changes are announced to screen readers.
|
|
52
|
+
*
|
|
53
|
+
* The comments are yours: each callback persists a change and the thread waits for it, then you
|
|
54
|
+
* pass the updated `comments` back. Throw (or reject) with a message written for the person and it
|
|
55
|
+
* shows where they acted. Bodies are stored mention values (`Thanks @[Asha Rao](u-12)`) and always
|
|
56
|
+
* render as text, never HTML.
|
|
57
|
+
*
|
|
58
|
+
* Wraps the shared `<wui-comment-thread>` element, which owns the boxes, keys and states; Razor
|
|
59
|
+
* `<app-comment-thread>` renders the same markup.
|
|
60
|
+
*
|
|
61
|
+
* @typedef {object} CommentThreadItem
|
|
62
|
+
* @property {string} id The comment's public id.
|
|
63
|
+
* @property {{ name: string, src?: string }} author Who wrote it; `src` is a photo URL.
|
|
64
|
+
* @property {string | number | Date} at When it was written: an ISO instant with its zone, epoch ms or a Date. Shown in IST.
|
|
65
|
+
* @property {string} [value] The stored body, with mentions as `@[Label](id)`.
|
|
66
|
+
* @property {boolean} [edited] Shows "Edited" beside the time.
|
|
67
|
+
* @property {boolean} [deleted] Shows "This comment was deleted." in place of the body; replies stay.
|
|
68
|
+
* @property {boolean} [canEdit] This person may edit it.
|
|
69
|
+
* @property {boolean} [canDelete] This person may delete it.
|
|
70
|
+
* @property {{ emoji: string, count: number, mine?: boolean }[]} [reactions]
|
|
71
|
+
* @property {CommentThreadItem[]} [replies] Replies, oldest first. Replies to a reply are not nested.
|
|
72
|
+
*
|
|
73
|
+
* @param {object} props
|
|
74
|
+
* @param {CommentThreadItem[]} [props.comments] Top-level comments, oldest first.
|
|
75
|
+
* @param {(body: string) => unknown | Promise<unknown>} [props.onPost] A new comment.
|
|
76
|
+
* @param {(parentId: string, body: string) => unknown | Promise<unknown>} [props.onReply]
|
|
77
|
+
* @param {(commentId: string, body: string) => unknown | Promise<unknown>} [props.onEdit]
|
|
78
|
+
* @param {(commentId: string) => unknown | Promise<unknown>} [props.onDelete]
|
|
79
|
+
* @param {(commentId: string, emoji: string) => unknown | Promise<unknown>} [props.onReact] Toggle
|
|
80
|
+
* this person's reaction.
|
|
81
|
+
* @param {{ value: string, label: string, description?: string, src?: string }[]} [props.people]
|
|
82
|
+
* The people the boxes offer after "@".
|
|
83
|
+
* @param {(query: string) => Promise<{ value: string, label: string, description?: string, src?: string }[]>} [props.loadPeople]
|
|
84
|
+
* Look people up instead of `people`.
|
|
85
|
+
* @param {string[]} [props.reactionChoices] The reactions the panel offers (default 👍 ❤️ 🎉 😄 👀 🙏).
|
|
86
|
+
* @param {boolean} [props.readOnly=false] Show the thread without the box, actions or reacting.
|
|
87
|
+
* @param {string} [props.label="Comments"] The list's accessible name.
|
|
88
|
+
* @param {string} [props.id] The root's id. Generated when omitted.
|
|
89
|
+
* @param {string} [props.className] Extra classes on the root.
|
|
90
|
+
*/
|
|
91
|
+
export default function AppCommentThread({ comments, onPost, onReply, onEdit, onDelete, onReact, people, loadPeople, reactionChoices, readOnly, label, id, className, ...rest }: {
|
|
92
|
+
comments?: CommentThreadItem[];
|
|
93
|
+
onPost?: (body: string) => unknown | Promise<unknown>;
|
|
94
|
+
onReply?: (parentId: string, body: string) => unknown | Promise<unknown>;
|
|
95
|
+
onEdit?: (commentId: string, body: string) => unknown | Promise<unknown>;
|
|
96
|
+
onDelete?: (commentId: string) => unknown | Promise<unknown>;
|
|
97
|
+
onReact?: (commentId: string, emoji: string) => unknown | Promise<unknown>;
|
|
98
|
+
people?: {
|
|
99
|
+
value: string;
|
|
100
|
+
label: string;
|
|
101
|
+
description?: string;
|
|
102
|
+
src?: string;
|
|
103
|
+
}[];
|
|
104
|
+
loadPeople?: (query: string) => Promise<{
|
|
105
|
+
value: string;
|
|
106
|
+
label: string;
|
|
107
|
+
description?: string;
|
|
108
|
+
src?: string;
|
|
109
|
+
}[]>;
|
|
110
|
+
reactionChoices?: string[];
|
|
111
|
+
readOnly?: boolean;
|
|
112
|
+
label?: string;
|
|
113
|
+
id?: string;
|
|
114
|
+
className?: string;
|
|
115
|
+
}): import("react").JSX.Element;
|
|
@@ -48,14 +48,48 @@
|
|
|
48
48
|
* on it, for in-page actions (open a drawer). Same nested-control rule as rowHref.
|
|
49
49
|
* @param {(row: object) => 'success'|'warning'|'danger'|'info'|undefined} [props.rowStatus] A coloured
|
|
50
50
|
* bar on the row's leading edge, e.g. danger for an overdue invoice. Undefined draws none.
|
|
51
|
+
* @param {string|number} [props.activeRowKey] The key (what `rowKey` returns) of the row whose record is
|
|
52
|
+
* open, e.g. in a detail pane beside the table. That row gets `aria-current="true"` and the subtle
|
|
53
|
+
* primary background; it is separate from `rowStatus`'s edge bar and from selected (checkbox) rows.
|
|
54
|
+
* Razor: `active-row-key` against each row's `data-row-key`.
|
|
51
55
|
* @param {boolean} [props.selectable=false] Render a leading checkbox column.
|
|
52
56
|
* @param {Set<string|number>} [props.selectedIds] Currently selected row keys.
|
|
53
57
|
* @param {(id: string|number) => void} [props.onToggleRow]
|
|
54
58
|
* @param {(checked: boolean) => void} [props.onToggleAll] Toggle all current rows.
|
|
59
|
+
* @param {(keys: Array<string|number>, checked: boolean) => void} [props.onSelectRange] Shift+click on a row
|
|
60
|
+
* checkbox selects (or clears) every row from the last clicked one to this one; this receives the keys
|
|
61
|
+
* of the other rows that change. Without it, `onToggleRow` is called once per key, so it must be safe
|
|
62
|
+
* to call several times in a row (a functional state update). Razor: built in.
|
|
55
63
|
* @param {(row: object) => import('react').ReactNode} [props.renderExpanded] When given, each row
|
|
56
64
|
* gets a leading expand toggle; the returned content renders in a full-width row beneath it.
|
|
65
|
+
* @param {boolean} [props.resizableColumns=false] Each column but the last gets a handle on its end edge:
|
|
66
|
+
* drag it, or focus it and press the arrow keys (Shift for bigger steps, Home or a double-click to
|
|
67
|
+
* undo). The table then keeps fixed widths measured from its rows, and the last column takes the rest.
|
|
68
|
+
* Razor: `resizable-columns`.
|
|
69
|
+
* @param {string} [props.viewKey] Remembers resized widths in this browser under this name (the same name
|
|
70
|
+
* `useTableView` takes). Razor: `view-key`, with `data-key` on each header cell.
|
|
71
|
+
* @param {string} [props.groupBy] A column key: rows gather under a header row per value of it, in the
|
|
72
|
+
* order each value first appears (sort within groups by sorting `rows`), each header collapsing its
|
|
73
|
+
* rows and showing their count. Razor: `group-by`, against the header cells' `data-key`.
|
|
74
|
+
* @param {(value: unknown, rows: object[]) => import('react').ReactNode} [props.groupLabel] A group
|
|
75
|
+
* header's label; without it the value shows as a cell would.
|
|
76
|
+
* @param {boolean} [props.virtual=false] Renders only the rows in view (plus a margin) for a long
|
|
77
|
+
* client-side list. Needs `maxHeight`; rows are taken to share one height, so it is not for
|
|
78
|
+
* `renderExpanded` or `stackOnMobile`. Razor: `virtual`.
|
|
79
|
+
* @param {(row: object) => boolean} [props.rowSaving] True while the row's add or change is on its way to
|
|
80
|
+
* the server: the row shows at once, tinted and marked busy, instead of waiting for the answer. Put an
|
|
81
|
+
* added row in `rows` straight away with this true (give it its final key if you can, so the outcome is
|
|
82
|
+
* announced). Razor: `data-wui-save-state="saving"` on the <tr>, or a server table's `saveRow`.
|
|
83
|
+
* @param {(row: object) => string|undefined} [props.rowSaveError] Why the row's last save failed: the row
|
|
84
|
+
* shows the error look with this line under its first cell. Put a changed row's old values back in `rows`
|
|
85
|
+
* as you set it, so the row shows what is really saved; keep a failed added row until the person retries
|
|
86
|
+
* or removes it. When a row leaves `rowSaving`, screen readers hear "Ana Rao saved." or "Ana Rao was not
|
|
87
|
+
* saved. <reason>" (the name is the first column's value). Razor: `data-wui-save-state="error"`.
|
|
88
|
+
*
|
|
89
|
+
* A sort or reorder of up to 200 rows glides each row to its new place; not under reduced motion, and not
|
|
90
|
+
* on a `virtual` table.
|
|
57
91
|
*/
|
|
58
|
-
export default function AppDataTable({ columns, rows, rowKey, sort, onSort, loading, skeletonRows, empty, emptyFiltered, sourceCount, rowActions, rowActionsLabel, pagination, ariaLabel, className, wrapperClassName, selectable, selectedIds, onToggleRow, onToggleAll, renderExpanded, density, striped, maxHeight, stickyFirstColumn, stickyActions, stackOnMobile, hiddenColumns, rowStatus, rowHref, onRowClick, ...rest }: {
|
|
92
|
+
export default function AppDataTable({ columns, rows, rowKey, sort, onSort, loading, skeletonRows, empty, emptyFiltered, sourceCount, rowActions, rowActionsLabel, pagination, ariaLabel, className, wrapperClassName, selectable, selectedIds, onToggleRow, onToggleAll, onSelectRange, renderExpanded, density, striped, maxHeight, stickyFirstColumn, stickyActions, stackOnMobile, hiddenColumns, rowStatus, rowHref, onRowClick, activeRowKey, resizableColumns, viewKey, groupBy, groupLabel, virtual, rowSaving, rowSaveError, ...rest }: {
|
|
59
93
|
columns: object[];
|
|
60
94
|
rows: object[];
|
|
61
95
|
rowKey?: (row: object, index: number) => string | number;
|
|
@@ -85,9 +119,18 @@ export default function AppDataTable({ columns, rows, rowKey, sort, onSort, load
|
|
|
85
119
|
rowHref?: (row: object) => string;
|
|
86
120
|
onRowClick?: (row: object) => void;
|
|
87
121
|
rowStatus?: (row: object) => 'success' | 'warning' | 'danger' | 'info' | undefined;
|
|
122
|
+
activeRowKey?: string | number;
|
|
88
123
|
selectable?: boolean;
|
|
89
124
|
selectedIds?: Set<string | number>;
|
|
90
125
|
onToggleRow?: (id: string | number) => void;
|
|
91
126
|
onToggleAll?: (checked: boolean) => void;
|
|
127
|
+
onSelectRange?: (keys: Array<string | number>, checked: boolean) => void;
|
|
92
128
|
renderExpanded?: (row: object) => import('react').ReactNode;
|
|
129
|
+
resizableColumns?: boolean;
|
|
130
|
+
viewKey?: string;
|
|
131
|
+
groupBy?: string;
|
|
132
|
+
groupLabel?: (value: unknown, rows: object[]) => import('react').ReactNode;
|
|
133
|
+
virtual?: boolean;
|
|
134
|
+
rowSaving?: (row: object) => boolean;
|
|
135
|
+
rowSaveError?: (row: object) => string | undefined;
|
|
93
136
|
}): import("react").JSX.Element;
|
|
@@ -25,6 +25,11 @@ import "@webority/ui-elements/elements/date-range";
|
|
|
25
25
|
* @param {'sm'|'md'|'lg'} [props.size] Control height tier, matching AppInput.
|
|
26
26
|
* @param {0|1|2|3|4|5|6} [props.firstDay] First weekday of the calendar, 0 Sunday to 6 Saturday. Unset, it
|
|
27
27
|
* follows the theme's `--wui-first-day` token, which is 1 (Monday) unless the product sets it.
|
|
28
|
+
* @param {(('today'|'last7Days'|'thisMonth'|'lastMonth'|'thisFinancialYear')|{ label: string, start: string, end: string })[]} [props.presets]
|
|
29
|
+
* Quick ranges, listed beside the calendar (above it on a phone); picking one fills the range and
|
|
30
|
+
* closes the calendar. An item is a name, resolved against today in IST (`thisFinancialYear` runs
|
|
31
|
+
* 1 April to 31 March; `thisMonth` and `lastMonth` span the whole month), or `{ label, start, end }`
|
|
32
|
+
* with ISO dates. A preset outside `min`/`max` is disabled.
|
|
28
33
|
* @param {string} [props.id]
|
|
29
34
|
* @param {string} [props.ariaLabel]
|
|
30
35
|
* @param {string} [props.className] Class to apply to the control element.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import "@webority/ui-elements/elements/drawer";
|
|
2
|
+
/**
|
|
3
|
+
* A panel over the page that is a side drawer from md up and a bottom sheet below it. The sheet
|
|
4
|
+
* rests on `snapPoints` (percent of the screen height), follows a finger on its handle or header,
|
|
5
|
+
* flicks to the next point and is dragged down to close; its handle is a vertical slider the arrow
|
|
6
|
+
* keys, Home and End also move. Focus moves in on open, Tab stays inside, Escape closes, and
|
|
7
|
+
* focus returns to what opened it. Controlled: set `open` and close it in `onClose`. Distinct from
|
|
8
|
+
* `AppModal`, which is a centred dialog on every screen. Wraps `<wui-drawer>`, which Razor
|
|
9
|
+
* `<app-drawer>` renders too. Place it where no ancestor has a transform, since it is fixed to the
|
|
10
|
+
* viewport.
|
|
11
|
+
*
|
|
12
|
+
* @param {object} props
|
|
13
|
+
* @param {boolean} [props.open=false]
|
|
14
|
+
* @param {() => void} [props.onClose] Called when the backdrop, Escape, the close button or a drag
|
|
15
|
+
* down asks to close it. It stays open until `open` becomes false.
|
|
16
|
+
* @param {string} [props.title] The heading, and the dialog's accessible name.
|
|
17
|
+
* @param {string} [props.subtitle] A line under the title.
|
|
18
|
+
* @param {string} [props.ariaLabel] The dialog's accessible name when there is no `title`.
|
|
19
|
+
* @param {'end'|'start'} [props.side="end"] Which edge the side drawer slides from.
|
|
20
|
+
* @param {'sm'|'md'|'lg'} [props.size="md"] The side drawer's width: 360, 480 or 640 px.
|
|
21
|
+
* @param {number[]} [props.snapPoints=[50, 90]] The sheet's resting heights, each 10 to 100 percent of the screen.
|
|
22
|
+
* @param {number} [props.defaultSnap=0] Which of the sorted snap points it opens on.
|
|
23
|
+
* @param {(index: number, percent: number) => void} [props.onSnapChange] Called when the sheet moves to another point.
|
|
24
|
+
* @param {boolean} [props.dismissible=true] Show the close button.
|
|
25
|
+
* @param {boolean} [props.staticBackdrop=false] The backdrop, Escape and a drag down no longer close it; only the close button or `open` can.
|
|
26
|
+
* @param {import('react').ReactNode} [props.footer] Pinned below the scrolling body.
|
|
27
|
+
* @param {string} [props.className]
|
|
28
|
+
* @param {import('react').ReactNode} props.children
|
|
29
|
+
*/
|
|
30
|
+
export default function AppDrawer({ open, onClose, title, subtitle, ariaLabel, side, size, snapPoints, defaultSnap, onSnapChange, dismissible, staticBackdrop, footer, className, children, ...rest }: {
|
|
31
|
+
open?: boolean;
|
|
32
|
+
onClose?: () => void;
|
|
33
|
+
title?: string;
|
|
34
|
+
subtitle?: string;
|
|
35
|
+
ariaLabel?: string;
|
|
36
|
+
side?: 'end' | 'start';
|
|
37
|
+
size?: 'sm' | 'md' | 'lg';
|
|
38
|
+
snapPoints?: number[];
|
|
39
|
+
defaultSnap?: number;
|
|
40
|
+
onSnapChange?: (index: number, percent: number) => void;
|
|
41
|
+
dismissible?: boolean;
|
|
42
|
+
staticBackdrop?: boolean;
|
|
43
|
+
footer?: import('react').ReactNode;
|
|
44
|
+
className?: string;
|
|
45
|
+
children: import('react').ReactNode;
|
|
46
|
+
}): import("react").JSX.Element;
|
|
@@ -15,8 +15,10 @@
|
|
|
15
15
|
* @param {string} [props.label] Tooltip + accessible-name fallback for the toggle.
|
|
16
16
|
* @param {"start"|"end"} [props.align="end"] Menu alignment.
|
|
17
17
|
* @param {string} [props.ariaLabel]
|
|
18
|
-
* @param {{ key: string, label?: string, icon?: string|import('react').ReactNode, image?: string, to?: string, onClick?: () => void, danger?: boolean, divider?: true }[]} [props.items]
|
|
18
|
+
* @param {{ key: string, label?: string, icon?: string|import('react').ReactNode, image?: string, to?: string, onClick?: () => void, danger?: boolean, shortcut?: string, divider?: true }[]} [props.items]
|
|
19
19
|
* `icon` is a glyph name OR a custom node (e.g. an iconsax glyph); `image` is a picture URL (external logo/avatar) — pass one.
|
|
20
|
+
* `shortcut` is the key that runs the item ("E"), drawn as a key chip at the end of the row; the
|
|
21
|
+
* page binds the key itself (useListShortcuts).
|
|
20
22
|
* An item with `divider: true` renders a separator instead of an action; it needs no
|
|
21
23
|
* `label`/`onClick`, just a unique `key`.
|
|
22
24
|
* @param {string} [props.menuClassName]
|
|
@@ -53,6 +55,7 @@ export default function AppDropdown({ icon, iconSize, toggleClassName, label, ar
|
|
|
53
55
|
to?: string;
|
|
54
56
|
onClick?: () => void;
|
|
55
57
|
danger?: boolean;
|
|
58
|
+
shortcut?: string;
|
|
56
59
|
divider?: true;
|
|
57
60
|
}[];
|
|
58
61
|
menuClassName?: string;
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @param {object} props
|
|
13
13
|
* @param {string|import('react').ReactNode} props.icon Semantic icon name for the bubble, or a custom node
|
|
14
|
+
* @param {"no-results"|"no-data"|"empty-inbox"|"no-notifications"|"no-files"|"no-access"|"offline"|"error"} [props.illustration]
|
|
15
|
+
* Decorative drawing by name, in theme colours. Replaces the icon bubble when set.
|
|
14
16
|
* @param {number} [props.iconSize=24]
|
|
15
17
|
* @param {"md"|"sm"} [props.size="md"]
|
|
16
18
|
* @param {import('react').ReactNode} props.title
|
|
@@ -19,8 +21,9 @@
|
|
|
19
21
|
* @param {string} [props.className]
|
|
20
22
|
* @param {import('react').CSSProperties} [props.style]
|
|
21
23
|
*/
|
|
22
|
-
export default function AppEmptyState({ icon, iconSize, size, title, text, action, className, style, ...rest }: {
|
|
24
|
+
export default function AppEmptyState({ icon, illustration, iconSize, size, title, text, action, className, style, ...rest }: {
|
|
23
25
|
icon: string | import('react').ReactNode;
|
|
26
|
+
illustration?: "no-results" | "no-data" | "empty-inbox" | "no-notifications" | "no-files" | "no-access" | "offline" | "error";
|
|
24
27
|
iconSize?: number;
|
|
25
28
|
size?: "md" | "sm";
|
|
26
29
|
title: import('react').ReactNode;
|