@webority/ui-react 0.80.9 → 0.82.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.
@@ -1 +1 @@
1
- import e from"./warnInvalidValue.js";import t from"./warnUnknownProps.js";import{jsx as n,jsxs as r}from"react/jsx-runtime";var i=[`sm`,`md`,`lg`];function a({multiple:a=!0,label:o,name:s,value:c,checked:l,onChange:u,children:d,count:f,size:p=`md`,className:m=``,...h}){return t(`AppChoiceChip`,h),e(`AppChoiceChip`,`size`,p,i),r(`label`,{className:`choice-chip${l?` checked`:``}${p===`sm`?` choice-chip-sm`:p===`lg`?` choice-chip-lg`:``}${m?` ${m}`:``}`,...h,children:[n(`input`,{type:a?`checkbox`:`radio`,name:s,value:c,checked:l,onChange:u}),n(`span`,{children:o??d}),f!=null&&n(`span`,{className:`count`,children:f})]})}export{a as default};
1
+ import e from"./warnInvalidValue.js";import t from"./warnUnknownProps.js";import{jsx as n,jsxs as r}from"react/jsx-runtime";var i=[`sm`,`md`,`lg`];function a({multiple:a=!0,label:o,name:s,value:c,checked:l,onChange:u,children:d,count:f,size:p=`md`,disabled:m=!1,className:h=``,...g}){return t(`AppChoiceChip`,g),e(`AppChoiceChip`,`size`,p,i),r(`label`,{className:`choice-chip${l?` checked`:``}${p===`sm`?` choice-chip-sm`:p===`lg`?` choice-chip-lg`:``}${h?` ${h}`:``}`,...g,children:[n(`input`,{type:a?`checkbox`:`radio`,name:s,value:c,checked:l,disabled:m,onChange:u}),n(`span`,{children:o??d}),f!=null&&n(`span`,{className:`count`,children:f})]})}export{a as default};
@@ -1 +1 @@
1
- import e from"./warnInvalidValue.js";import t from"./warnUnknownProps.js";import n from"./AppIcon.js";import{useEffect as r,useId as i,useLayoutEffect as a,useRef as o}from"react";import{jsx as s,jsxs as c}from"react/jsx-runtime";var l={sm:`segmented-sm`,md:``,lg:`segmented-lg`,xl:`wui-segmented-xl`};function u({options:u=[],value:d,onChange:f,label:p,name:m,size:h=`md`,fullWidth:g=!1,bordered:_=!0,disabled:v=!1,labelVisible:y=!1,className:b=``,...x}){t(`AppSegmented`,x),e(`AppSegmented`,`size`,h,Object.keys(l));let S=i(),C=m||S,w=o(null),T=o(null),E=[`segmented`,l[h]??``,g?`segmented-full`:``,_?``:`wui-segmented-borderless`,v?`is-disabled`:``,b].filter(Boolean).join(` `);a(()=>{let e=w.current,t=T.current;if(!e||!t)return;let n=n=>{let r=e.querySelector(`.segmented-option:has(.segmented-input:checked)`);if(!r||!e.offsetWidth){t.style.opacity=`0`;return}n||e.classList.remove(`is-animated`),t.style.width=`${r.offsetWidth}px`,t.style.transform=`translateX(${r.offsetLeft}px)`,t.style.opacity=`1`,n||requestAnimationFrame(()=>w.current?.classList.add(`is-animated`))};n(!0);let r=typeof ResizeObserver<`u`?new ResizeObserver(()=>n(!1)):null;return r?.observe(e),()=>r?.disconnect()},[d,u,h,g,y]),r(()=>{let e=requestAnimationFrame(()=>w.current?.classList.add(`is-animated`));return()=>cancelAnimationFrame(e)},[]);let D=c(`div`,{ref:w,className:E,role:`radiogroup`,"aria-label":p,"aria-disabled":v||void 0,...x,children:[s(`span`,{className:`segmented-thumb`,ref:T,"aria-hidden":`true`}),u.map(e=>c(`label`,{className:`segmented-option`,children:[s(`input`,{type:`radio`,className:`segmented-input`,name:C,value:e.value,checked:e.value===d,disabled:v||e.disabled,onChange:()=>f?.(e.value)}),e.icon&&s(n,{name:e.icon,size:13}),e.note?c(`span`,{className:`segmented-option-text`,children:[s(`span`,{className:`segmented-option-label`,children:e.label}),s(`span`,{className:`segmented-option-note`,children:e.note})]}):e.label,e.count!=null&&s(`span`,{className:`wui-segmented-option-count`,children:e.count})]},e.value))]});return!y||!p?D:c(`div`,{className:`field`,children:[s(`span`,{className:`label`,"aria-hidden":`true`,children:p}),D]})}export{u as default};
1
+ import e from"./warnInvalidValue.js";import t from"./warnUnknownProps.js";import n from"./AppIcon.js";import r from"./warnDeprecatedValue.js";import{useEffect as i,useId as a,useLayoutEffect as o,useRef as s}from"react";import{jsx as c,jsxs as l}from"react/jsx-runtime";var u={sm:`segmented-sm`,md:``,lg:`segmented-lg`},d={xl:{use:`lg`,removeIn:`0.83.0`}};function f({options:f=[],value:p,onChange:m,label:h,name:g,size:_=`md`,fullWidth:v=!1,bordered:y=!0,disabled:b=!1,labelVisible:x=!1,className:S=``,...C}){t(`AppSegmented`,C),r(`AppSegmented`,`size`,_,d);let w=d[_]?.use??_;e(`AppSegmented`,`size`,w,Object.keys(u));let T=a(),E=g||T,D=s(null),O=s(null),k=[`segmented`,u[w]??``,v?`segmented-full`:``,y?``:`wui-segmented-borderless`,b?`is-disabled`:``,S].filter(Boolean).join(` `);o(()=>{let e=D.current,t=O.current;if(!e||!t)return;let n=n=>{let r=e.querySelector(`.segmented-option:has(.segmented-input:checked)`);if(!r||!e.offsetWidth){t.style.opacity=`0`;return}n||e.classList.remove(`is-animated`),t.style.width=`${r.offsetWidth}px`,t.style.transform=`translateX(${r.offsetLeft}px)`,t.style.opacity=`1`,n||requestAnimationFrame(()=>D.current?.classList.add(`is-animated`))};n(!0);let r=typeof ResizeObserver<`u`?new ResizeObserver(()=>n(!1)):null;return r?.observe(e),()=>r?.disconnect()},[p,f,_,v,x]),i(()=>{let e=requestAnimationFrame(()=>D.current?.classList.add(`is-animated`));return()=>cancelAnimationFrame(e)},[]);let A=l(`div`,{ref:D,className:k,role:`radiogroup`,"aria-label":h,"aria-disabled":b||void 0,...C,children:[c(`span`,{className:`segmented-thumb`,ref:O,"aria-hidden":`true`}),f.map(e=>l(`label`,{className:`segmented-option`,children:[c(`input`,{type:`radio`,className:`segmented-input`,name:E,value:e.value,checked:e.value===p,disabled:b||e.disabled,onChange:()=>m?.(e.value)}),e.icon&&c(n,{name:e.icon,size:13}),e.note?l(`span`,{className:`segmented-option-text`,children:[c(`span`,{className:`segmented-option-label`,children:e.label}),c(`span`,{className:`segmented-option-note`,children:e.note})]}):e.label,e.count!=null&&c(`span`,{className:`wui-segmented-option-count`,children:e.count})]},e.value))]});return!x||!h?A:l(`div`,{className:`field`,children:[c(`span`,{className:`label`,"aria-hidden":`true`,children:h}),A]})}export{f as default};
@@ -1 +1 @@
1
- import e from"./warnInvalidValue.js";import t from"./warnUnknownProps.js";import n from"./AppActionIcon.js";import r from"./AppSegmented.js";import{DEFAULT_THEME_EFFECT as i,DEFAULT_THEME_STORAGE_KEY as a,THEME_CHANGE_EVENT as o,THEME_EFFECTS as s,THEME_MODES as c,applyTheme as l,nextTheme as u,readStoredTheme as d,resolveTheme as f,storeTheme as p,transitionTheme as m,watchSystemTheme as h}from"@webority/ui-elements/helpers";import{useCallback as g,useEffect as _,useId as v,useState as y}from"react";import{jsx as b}from"react/jsx-runtime";import{flushSync as x}from"react-dom";var S={light:`sun`,dark:`moon`,auto:`monitor`},C={light:`light`,dark:`dark`,auto:`follows your device`},w=[`icon`,`segmented`],T={sm:16,md:20,lg:24,xl:28};function E({variant:E=`icon`,effect:D=i,includeAuto:O=!0,storageKey:k=a,duration:A,label:j=`Theme`,lightLabel:M=`Light`,darkLabel:N=`Dark`,autoLabel:P=`System`,name:F,size:I=`md`,tooltipPlacement:L=`auto`,onChange:R,className:z=``,...B}){t(`AppThemeToggle`,B),e(`AppThemeToggle`,`variant`,E,w),e(`AppThemeToggle`,`effect`,D,s),e(`AppThemeToggle`,`size`,I,Object.keys(T));let V=g(e=>e===`auto`&&!O?f(e):e,[O]),[H,U]=y(()=>V(typeof window>`u`?`auto`:d(k))),W=v(),G=F||W;_(()=>{let e=document.documentElement.getAttribute(`data-theme`);c.includes(e)?U(V(e)):l(d(k))},[]),_(()=>{let e=e=>{let t=e.detail?.preference;c.includes(t)&&U(V(t))};return document.addEventListener(o,e),()=>document.removeEventListener(o,e)},[V]),_(()=>h(()=>{document.documentElement.getAttribute(`data-theme`)===`auto`&&l(`auto`)}),[]);let K=g((e,t)=>{let n=t?.getBoundingClientRect?.()??{left:0,top:0,width:0,height:0},r={x:n.left+n.width/2,y:n.top+n.height/2};m(()=>{l(e),p(e,k),x(()=>U(e)),R?.(e)},{effect:D,to:f(e),origin:r,duration:A})},[k,D,A,R]);if(E===`segmented`){let e=[{value:`light`,label:M,icon:S.light},{value:`dark`,label:N,icon:S.dark}];return O&&e.push({value:`auto`,label:P,icon:S.auto}),b(r,{options:e,value:H,name:G,label:j,size:I,className:[`wui-theme-toggle`,`wui-theme-toggle-segmented`,z].filter(Boolean).join(` `),onChange:e=>{if(e===H)return;let t=document.querySelector(`.segmented-input[name="${CSS.escape(G)}"][value="${e}"]`);K(e,t?.closest(`.segmented-option`)??t)}})}return b(n,{icon:S[H],label:`${j}: ${C[H]}`,size:T[I]??T.md,tooltipPlacement:L,onClick:e=>K(u(H,{includeAuto:O}),e.currentTarget),className:[`wui-theme-toggle`,z].filter(Boolean).join(` `)})}export{E as default};
1
+ import e from"./warnInvalidValue.js";import t from"./warnUnknownProps.js";import n from"./AppActionIcon.js";import r from"./AppSegmented.js";import{DEFAULT_THEME_EFFECT as i,DEFAULT_THEME_STORAGE_KEY as a,THEME_CHANGE_EVENT as o,THEME_EFFECTS as s,THEME_MODES as c,applyTheme as l,nextTheme as u,readStoredTheme as d,resolveTheme as f,storeTheme as p,transitionTheme as m,watchSystemTheme as h}from"@webority/ui-elements/helpers";import{useCallback as g,useEffect as _,useId as v,useState as y}from"react";import{jsx as b}from"react/jsx-runtime";import{flushSync as x}from"react-dom";var S={light:`sun`,dark:`moon`,auto:`monitor`},C={light:`light`,dark:`dark`,auto:`follows your device`},w=[`icon`,`segmented`],T={sm:16,md:20,lg:24,xl:28};function E({variant:E=`icon`,effect:D=i,includeAuto:O=!0,storageKey:k=a,duration:A,label:j=`Theme`,lightLabel:M=`Light`,darkLabel:N=`Dark`,autoLabel:P=`System`,name:F,size:I=`md`,tooltipPlacement:L=`auto`,onChange:R,className:z=``,...B}){t(`AppThemeToggle`,B),e(`AppThemeToggle`,`variant`,E,w),e(`AppThemeToggle`,`effect`,D,s),e(`AppThemeToggle`,`size`,I,Object.keys(T));let V=g(e=>e===`auto`&&!O?f(e):e,[O]),[H,U]=y(()=>V(typeof window>`u`?`auto`:d(k))),W=v(),G=F||W;_(()=>{let e=document.documentElement.getAttribute(`data-theme`);c.includes(e)?U(V(e)):l(d(k))},[]),_(()=>{let e=e=>{let t=e.detail?.preference;c.includes(t)&&U(V(t))};return document.addEventListener(o,e),()=>document.removeEventListener(o,e)},[V]),_(()=>h(()=>{document.documentElement.getAttribute(`data-theme`)===`auto`&&l(`auto`)}),[]);let K=g((e,t)=>{let n=t?.getBoundingClientRect?.()??{left:0,top:0,width:0,height:0},r={x:n.left+n.width/2,y:n.top+n.height/2};m(()=>{l(e),p(e,k),x(()=>U(e)),R?.(e)},{effect:D,to:f(e),origin:r,duration:A})},[k,D,A,R]);if(E===`segmented`){let e=[{value:`light`,label:M,icon:S.light},{value:`dark`,label:N,icon:S.dark}];return O&&e.push({value:`auto`,label:P,icon:S.auto}),b(r,{options:e,value:H,name:G,label:j,size:I===`xl`?`lg`:I,className:[`wui-theme-toggle`,`wui-theme-toggle-segmented`,z].filter(Boolean).join(` `),onChange:e=>{if(e===H)return;let t=document.querySelector(`.segmented-input[name="${CSS.escape(G)}"][value="${e}"]`);K(e,t?.closest(`.segmented-option`)??t)}})}return b(n,{icon:S[H],label:`${j}: ${C[H]}`,size:T[I]??T.md,tooltipPlacement:L,onClick:e=>K(u(H,{includeAuto:O}),e.currentTarget),className:[`wui-theme-toggle`,z].filter(Boolean).join(` `)})}export{E as default};
@@ -12,9 +12,10 @@
12
12
  * @param {import('react').ReactNode} [props.count] A matching-row count, e.g. "Active 12".
13
13
  * Shown as a small badge that inverts when the chip is selected.
14
14
  * @param {'sm'|'md'|'lg'} [props.size='md'] Pill size — padding, gap and font step together.
15
+ * @param {boolean} [props.disabled=false] The chip dims and cannot be picked.
15
16
  * @param {string} [props.className]
16
17
  */
17
- export default function AppChoiceChip({ multiple, label, name, value, checked, onChange, children, count, size, className, ...rest }: {
18
+ export default function AppChoiceChip({ multiple, label, name, value, checked, onChange, children, count, size, disabled, className, ...rest }: {
18
19
  multiple?: boolean;
19
20
  label?: import('react').ReactNode;
20
21
  name?: string;
@@ -24,5 +25,6 @@ export default function AppChoiceChip({ multiple, label, name, value, checked, o
24
25
  children: import('react').ReactNode;
25
26
  count?: import('react').ReactNode;
26
27
  size?: 'sm' | 'md' | 'lg';
28
+ disabled?: boolean;
27
29
  className?: string;
28
30
  }): import("react").JSX.Element;
@@ -14,7 +14,7 @@
14
14
  * column beside the fields from lg up; below that it stacks.
15
15
  * @param {'top'|'start'} [props.labels='top'] `start` puts each field's label beside its control
16
16
  * (one field per row) from md up; below that labels sit on top.
17
- * @param {'comfortable'|'compact'} [props.density='comfortable'] `compact` uses 36px controls and
17
+ * @param {'comfortable'|'compact'} [props.density='comfortable'] `compact` uses 32px controls and
18
18
  * tighter gaps, for admin screens and dialogs.
19
19
  * @param {2|3|4} [props.headingLevel=3] Heading level of the section title, so it nests under the page or drawer heading.
20
20
  * @param {string} [props.className]
@@ -1,14 +1,49 @@
1
+ /**
2
+ * A segmented control — 2–4 mutually-exclusive options shown side by side, all
3
+ * visible at once. The canonical use is a theme switch (Light / Dark / System)
4
+ * or a compact view/range toggle above a chart.
5
+ *
6
+ * Past four options the row runs out of width — reach for `AppSelect` instead.
7
+ * For a boolean use `AppSwitch`; for a filter that can be off use `AppChoiceChip`.
8
+ *
9
+ * Built on real `<input type="radio">` elements inside labels, so arrow-key
10
+ * navigation, the single tab stop, and the "2 of 3" screen-reader announcement all
11
+ * come from the browser rather than hand-written key handling — and the control
12
+ * posts inside a plain form with no JavaScript.
13
+ *
14
+ * @param {object} props
15
+ * @param {{ value: string, label: string, note?: string, icon?: string, disabled?: boolean, count?: number }[]} props.options
16
+ * `note` renders as a smaller, muted sub-line under the label — a supporting detail
17
+ * ("Last 7 days") without shrinking the label itself. Optional; segments without one are
18
+ * unaffected.
19
+ * @param {string} props.value The selected option's value.
20
+ * @param {(value: string) => void} props.onChange
21
+ * @param {string} props.label Accessible name for the group.
22
+ * @param {string} [props.name] Field name. Defaults to a generated one.
23
+ * @param {'sm'|'md'|'lg'|'xl'} [props.size='md'] Heights 32, 36 and 44px. xl is deprecated (use lg) and is removed in 0.83.0.
24
+ * @param {boolean} [props.fullWidth=false] Segments share the row equally, filling the container.
25
+ * @param {boolean} [props.bordered=true] Draws the edge and soft shadow of the selected thumb. `false` keeps a flat thumb.
26
+ * @param {boolean} [props.disabled=false] Disables the whole control.
27
+ * @param {boolean} [props.labelVisible=false] Shows the field label above the control. The accessible name stays either way.
28
+ * @param {string} [props.className]
29
+ */
1
30
  export default function AppSegmented({ options, value, onChange, label, name, size, fullWidth, bordered, disabled, labelVisible, className, ...rest }: {
2
- [x: string]: any;
31
+ options: {
32
+ value: string;
33
+ label: string;
34
+ note?: string;
35
+ icon?: string;
36
+ disabled?: boolean;
37
+ count?: number;
38
+ }[];
39
+ value: string;
40
+ onChange: (value: string) => void;
41
+ label: string;
42
+ name?: string;
43
+ size?: 'sm' | 'md' | 'lg' | 'xl';
44
+ fullWidth?: boolean;
3
45
  bordered?: boolean;
4
- className?: string;
5
46
  disabled?: boolean;
6
- fullWidth?: boolean;
7
- label: any;
8
47
  labelVisible?: boolean;
9
- name: any;
10
- onChange: any;
11
- options?: any[];
12
- size?: string;
13
- value: any;
48
+ className?: string;
14
49
  }): import("react").JSX.Element;
@@ -30,7 +30,7 @@
30
30
  * @param {string} [props.darkLabel="Dark"] The segmented variant's option text for dark.
31
31
  * @param {string} [props.autoLabel="System"] The segmented variant's option text for auto.
32
32
  * @param {string} [props.name] The segmented variant's field name (what groups its radios). Defaults to a generated one.
33
- * @param {"sm"|"md"|"lg"|"xl"} [props.size="md"] The disc's glyph size (16/20/24/28px, the disc scales with it) or the segmented strip's size.
33
+ * @param {"sm"|"md"|"lg"|"xl"} [props.size="md"] The disc's glyph size (16/20/24/28px, the disc scales with it) or the segmented strip's size (xl draws the lg strip).
34
34
  * @param {"auto"|"top"|"bottom"|"start"|"end"} [props.tooltipPlacement="auto"] The disc's preferred tooltip side.
35
35
  * @param {(mode: "light"|"dark"|"auto") => void} [props.onChange] Fires with the new mode once it is applied.
36
36
  * @param {string} [props.className]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/ui-react",
3
- "version": "0.80.9",
3
+ "version": "0.82.0",
4
4
  "description": "Webority shared React component library — App* primitives on react-bootstrap + the @webority/theme design system.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
@@ -27,8 +27,8 @@
27
27
  },
28
28
  "sideEffects": false,
29
29
  "dependencies": {
30
- "@webority/theme": "0.80.9",
31
- "@webority/ui-elements": "0.80.9"
30
+ "@webority/theme": "0.82.0",
31
+ "@webority/ui-elements": "0.82.0"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "@webority/analytics": "^0.25.0",