@allxsmith/bestax-bulma 5.49.0 → 5.50.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.
@@ -0,0 +1,117 @@
1
+ /* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { forwardRef, useEffect } from 'react';
4
+ import { usePrefixedClassNames, classNames, prefixedClassNames } from '../helpers/classNames.js';
5
+ import { useClassPrefix } from '../helpers/Config.js';
6
+ import { useBulmaClasses } from '../helpers/useBulmaClasses.js';
7
+ import { warnOnce } from '../helpers/devWarnings.js';
8
+
9
+ const validRingProgressColors = [
10
+ 'primary',
11
+ 'link',
12
+ 'info',
13
+ 'success',
14
+ 'warning',
15
+ 'danger',
16
+ 'black',
17
+ 'dark',
18
+ 'light',
19
+ 'white',
20
+ ];
21
+ const validRingProgressSizes = ['small', 'medium', 'large'];
22
+ const clamp$2 = (value, low, high) => Math.min(Math.max(value, low), high);
23
+ /**
24
+ * The `RingProgress` component draws a value as a ring that fills as it grows, with anything you pass shown in the middle.
25
+ *
26
+ * It's a `progressbar` for a task moving toward done, or a `meter` with
27
+ * `isMeter` for a level within a range, named by `label`. With `sections`
28
+ * it draws several values around one ring and is an image whose name lists
29
+ * them. It has no state for work with no value: that's `Loader`.
30
+ *
31
+ * @function
32
+ * @param {RingProgressProps} props - Props for the RingProgress component.
33
+ * @param {React.Ref<HTMLDivElement>} ref - Forwarded ref to the root `<div>`.
34
+ * @returns {JSX.Element} The rendered ring.
35
+ *
36
+ * @example
37
+ * <RingProgress value={72} label="Upload" color="success">
38
+ * 72%
39
+ * </RingProgress>
40
+ */
41
+ const RingProgress = forwardRef(({ className, textColor, bgColor, value, max = 100, sections, label, isMeter, color, size, isRounded, children, ...props }, ref) => {
42
+ const { bulmaHelperClasses, rest } = useBulmaClasses({
43
+ color: textColor,
44
+ backgroundColor: bgColor,
45
+ ...props,
46
+ });
47
+ const named = Boolean(label || rest['aria-label'] || rest['aria-labelledby']);
48
+ const mixed = sections !== undefined && value !== undefined;
49
+ useEffect(() => {
50
+ if (!named) {
51
+ warnOnce('RingProgress:unnamed', '[bestax-bulma] <RingProgress> has no accessible name. Pass ' +
52
+ 'label, so a screen reader can say what the ring shows.');
53
+ }
54
+ if (mixed) {
55
+ warnOnce('RingProgress:value-and-sections', '[bestax-bulma] <RingProgress> was given both value and sections. ' +
56
+ 'It draws the sections and ignores value.');
57
+ }
58
+ }, [named, mixed]);
59
+ const total = max > 0 ? max : 100;
60
+ const share = (part) => (clamp$2(part, 0, total) / total) * 100;
61
+ // Each arc starts where the one before ended, and the last stops at the
62
+ // top, so a total over max fills the ring and no more.
63
+ const arcs = [];
64
+ if (sections) {
65
+ let start = 0;
66
+ for (const section of sections) {
67
+ const length = Math.min(share(section.value), 100 - start);
68
+ arcs.push({ start, length, color: section.color });
69
+ start += length;
70
+ }
71
+ }
72
+ else {
73
+ arcs.push({ start: 0, length: share(value ?? 0) });
74
+ }
75
+ const rootClass = usePrefixedClassNames('ring-progress', {
76
+ [`is-${size}`]: !!size && validRingProgressSizes.includes(size),
77
+ [`is-${color}`]: !!color &&
78
+ validRingProgressColors.includes(color),
79
+ 'is-rounded': !!isRounded,
80
+ 'has-sections': !!sections,
81
+ });
82
+ const ringClass = usePrefixedClassNames('ring-progress-ring');
83
+ const trackClass = usePrefixedClassNames('ring-progress-track');
84
+ const arcClass = usePrefixedClassNames('ring-progress-arc');
85
+ const labelClass = usePrefixedClassNames('ring-progress-label');
86
+ // A section's color class, prefixed like the rest.
87
+ const classPrefix = useClassPrefix();
88
+ const roleProps = sections
89
+ ? {
90
+ role: 'img',
91
+ 'aria-label': [
92
+ label || rest['aria-label'],
93
+ sections
94
+ .map((section, i) => `${section.label} ${Math.round(arcs[i].length)}%`)
95
+ .join(', '),
96
+ ]
97
+ .filter(Boolean)
98
+ .join(': '),
99
+ }
100
+ : {
101
+ role: isMeter ? 'meter' : 'progressbar',
102
+ 'aria-valuenow': clamp$2(value ?? 0, 0, total),
103
+ 'aria-valuemin': 0,
104
+ 'aria-valuemax': total,
105
+ 'aria-label': label || rest['aria-label'],
106
+ };
107
+ return (jsxs("div", { ref: ref, className: classNames(rootClass, bulmaHelperClasses, className), ...rest, ...roleProps, children: [jsxs("svg", { className: ringClass, viewBox: "0 0 100 100", "aria-hidden": "true", children: [jsx("circle", { className: trackClass, cx: "50", cy: "50", r: "42" }), arcs.map((arc, i) => arc.length > 0 && (jsx("circle", { className: classNames(arcClass, arc.color &&
108
+ validRingProgressColors.includes(arc.color) &&
109
+ prefixedClassNames(classPrefix, `is-${arc.color}`)), cx: "50", cy: "50", r: "42", pathLength: 100, style: {
110
+ '--ring-progress-length': arc.length,
111
+ '--ring-progress-start': arc.start,
112
+ } }, i)))] }), children !== undefined && children !== null && (jsx("div", { className: labelClass, "aria-hidden": "true", children: children }))] }));
113
+ });
114
+ RingProgress.displayName = 'RingProgress';
115
+
116
+ export { RingProgress };
117
+ //# sourceMappingURL=RingProgress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RingProgress.js","sources":["../../../src/elements/RingProgress.tsx"],"sourcesContent":["import React, { forwardRef, useEffect } from 'react';\nimport {\n classNames,\n prefixedClassNames,\n usePrefixedClassNames,\n} from '../helpers/classNames';\nimport { useClassPrefix } from '../helpers/Config';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\nimport { warnOnce } from '../helpers/devWarnings';\n\nconst validRingProgressColors = [\n 'primary',\n 'link',\n 'info',\n 'success',\n 'warning',\n 'danger',\n 'black',\n 'dark',\n 'light',\n 'white',\n] as const;\n/** The Bulma colors an arc takes, the ones `Progress` takes. */\nexport type RingProgressColor = (typeof validRingProgressColors)[number];\n\nconst validRingProgressSizes = ['small', 'medium', 'large'] as const;\n\n/** One colored part of a ring drawn in sections. */\nexport interface RingProgressSection {\n /** Its size, in the same units as the ring's `max`. */\n value: number;\n /** Its color. Without one, it takes the ring's. */\n color?: RingProgressColor;\n /** What it is, such as \"Photos\", read in the ring's name with its share. */\n label: string;\n}\n\n/**\n * Props for the RingProgress component. The helper props, the other\n * attributes and the `ref` land on its root `<div>`.\n *\n * @extraProp {React.Ref<HTMLDivElement>} [ref] - Ref forwarded to the root `<div>`.\n * @extraProp {string} [aria-labelledby] - The id of a visible heading that names the ring, in place of `label`. With `sections`, use `label`, since a name from here replaces the one that lists the values.\n * @extraProp {string} [aria-valuetext] - What a screen reader says for the value, such as \"7 of 10 tasks\". Without it, the value is read as a percentage.\n */\nexport interface RingProgressProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'color' | 'role'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Additional CSS classes to apply. */\n className?: string;\n /**\n * How far along it is, from 0 to `max`. Values outside that range are\n * drawn, and read, at the nearest end. Ignored with `sections`.\n */\n value?: number;\n /** The value that fills the ring. */\n max?: number;\n /**\n * Several values around one ring, in order clockwise from the top, each\n * with its own color and label. The ring is then an image whose name\n * writes them out, such as \"Storage: Documents 40%, Photos 15%\", since a\n * screen reader can't take several values from one element. A total over\n * `max` fills the ring and stops.\n */\n sections?: RingProgressSection[];\n /**\n * What it shows, such as \"Upload\" or \"Storage\". It names the ring, so it's\n * read with the value. A development build warns when the ring has no\n * name.\n */\n label?: string;\n /**\n * A level within a range, such as storage used or a score, rather than a\n * task moving toward done: `role=\"meter\"` in place of `role=\"progressbar\"`.\n * Ignored with `sections`.\n */\n isMeter?: boolean;\n /** The arc's color, and the color of sections without one. */\n color?: RingProgressColor;\n /** The ring's size. */\n size?: (typeof validRingProgressSizes)[number];\n /** Rounds the ends of the arc. */\n isRounded?: boolean;\n /**\n * What sits in the middle of the ring, such as the value as text. It's\n * hidden from assistive tech, which reads the value from the ring itself,\n * so the value isn't heard twice. Say anything more, such as \"7 of 10\n * tasks\", in `aria-valuetext`.\n */\n children?: React.ReactNode;\n /** Text color helper. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Background color helper. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n}\n\n/** An arc's place on the ring, in percent of the way round. */\ninterface Arc {\n start: number;\n length: number;\n color?: RingProgressColor;\n}\n\nconst clamp = (value: number, low: number, high: number) =>\n Math.min(Math.max(value, low), high);\n\n/**\n * The `RingProgress` component draws a value as a ring that fills as it grows, with anything you pass shown in the middle.\n *\n * It's a `progressbar` for a task moving toward done, or a `meter` with\n * `isMeter` for a level within a range, named by `label`. With `sections`\n * it draws several values around one ring and is an image whose name lists\n * them. It has no state for work with no value: that's `Loader`.\n *\n * @function\n * @param {RingProgressProps} props - Props for the RingProgress component.\n * @param {React.Ref<HTMLDivElement>} ref - Forwarded ref to the root `<div>`.\n * @returns {JSX.Element} The rendered ring.\n *\n * @example\n * <RingProgress value={72} label=\"Upload\" color=\"success\">\n * 72%\n * </RingProgress>\n */\nexport const RingProgress = forwardRef<HTMLDivElement, RingProgressProps>(\n (\n {\n className,\n textColor,\n bgColor,\n value,\n max = 100,\n sections,\n label,\n isMeter,\n color,\n size,\n isRounded,\n children,\n ...props\n },\n ref\n ) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n\n const named = Boolean(\n label || rest['aria-label'] || rest['aria-labelledby']\n );\n const mixed = sections !== undefined && value !== undefined;\n useEffect(() => {\n if (!named) {\n warnOnce(\n 'RingProgress:unnamed',\n '[bestax-bulma] <RingProgress> has no accessible name. Pass ' +\n 'label, so a screen reader can say what the ring shows.'\n );\n }\n if (mixed) {\n warnOnce(\n 'RingProgress:value-and-sections',\n '[bestax-bulma] <RingProgress> was given both value and sections. ' +\n 'It draws the sections and ignores value.'\n );\n }\n }, [named, mixed]);\n\n const total = max > 0 ? max : 100;\n const share = (part: number) => (clamp(part, 0, total) / total) * 100;\n\n // Each arc starts where the one before ended, and the last stops at the\n // top, so a total over max fills the ring and no more.\n const arcs: Arc[] = [];\n if (sections) {\n let start = 0;\n for (const section of sections) {\n const length = Math.min(share(section.value), 100 - start);\n arcs.push({ start, length, color: section.color });\n start += length;\n }\n } else {\n arcs.push({ start: 0, length: share(value ?? 0) });\n }\n\n const rootClass = usePrefixedClassNames('ring-progress', {\n [`is-${size}`]:\n !!size && (validRingProgressSizes as readonly string[]).includes(size),\n [`is-${color}`]:\n !!color &&\n (validRingProgressColors as readonly string[]).includes(color),\n 'is-rounded': !!isRounded,\n 'has-sections': !!sections,\n });\n const ringClass = usePrefixedClassNames('ring-progress-ring');\n const trackClass = usePrefixedClassNames('ring-progress-track');\n const arcClass = usePrefixedClassNames('ring-progress-arc');\n const labelClass = usePrefixedClassNames('ring-progress-label');\n // A section's color class, prefixed like the rest.\n const classPrefix = useClassPrefix();\n\n const roleProps = sections\n ? {\n role: 'img',\n 'aria-label': [\n label || rest['aria-label'],\n sections\n .map(\n (section, i) =>\n `${section.label} ${Math.round(arcs[i].length)}%`\n )\n .join(', '),\n ]\n .filter(Boolean)\n .join(': '),\n }\n : {\n role: isMeter ? 'meter' : 'progressbar',\n 'aria-valuenow': clamp(value ?? 0, 0, total),\n 'aria-valuemin': 0,\n 'aria-valuemax': total,\n 'aria-label': label || rest['aria-label'],\n };\n\n return (\n <div\n ref={ref}\n className={classNames(rootClass, bulmaHelperClasses, className)}\n {...rest}\n {...roleProps}\n >\n <svg className={ringClass} viewBox=\"0 0 100 100\" aria-hidden=\"true\">\n <circle className={trackClass} cx=\"50\" cy=\"50\" r=\"42\" />\n {arcs.map(\n (arc, i) =>\n arc.length > 0 && (\n <circle\n key={i}\n className={classNames(\n arcClass,\n arc.color &&\n (validRingProgressColors as readonly string[]).includes(\n arc.color\n ) &&\n prefixedClassNames(classPrefix, `is-${arc.color}`)\n )}\n cx=\"50\"\n cy=\"50\"\n r=\"42\"\n pathLength={100}\n style={\n {\n '--ring-progress-length': arc.length,\n '--ring-progress-start': arc.start,\n } as React.CSSProperties\n }\n />\n )\n )}\n </svg>\n {children !== undefined && children !== null && (\n // The ring's value is already read from its role, and not every\n // browser keeps a meter's content out of the tree, so the middle\n // is for the eye only.\n <div className={labelClass} aria-hidden=\"true\">\n {children}\n </div>\n )}\n </div>\n );\n }\n);\n\nRingProgress.displayName = 'RingProgress';\n\nexport default RingProgress;\n"],"names":["clamp","_jsxs","_jsx"],"mappings":";;;;;;;;AAcA,MAAM,uBAAuB,GAAG;IAC9B,SAAS;IACT,MAAM;IACN,MAAM;IACN,SAAS;IACT,SAAS;IACT,QAAQ;IACR,OAAO;IACP,MAAM;IACN,OAAO;IACP,OAAO;CACC;AAIV,MAAM,sBAAsB,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAU;AA+EpE,MAAMA,OAAK,GAAG,CAAC,KAAa,EAAE,GAAW,EAAE,IAAY,KACrD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC;AAEtC;;;;;;;;;;;;;;;;;AAiBG;AACI,MAAM,YAAY,GAAG,UAAU,CACpC,CACE,EACE,SAAS,EACT,SAAS,EACT,OAAO,EACP,KAAK,EACL,GAAG,GAAG,GAAG,EACT,QAAQ,EACR,KAAK,EACL,OAAO,EACP,KAAK,EACL,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EACD,GAAG,KACD;AACF,IAAA,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC;AACnD,QAAA,KAAK,EAAE,SAAS;AAChB,QAAA,eAAe,EAAE,OAAO;AACxB,QAAA,GAAG,KAAK;AACT,KAAA,CAAC;AAEF,IAAA,MAAM,KAAK,GAAG,OAAO,CACnB,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,iBAAiB,CAAC,CACvD;IACD,MAAM,KAAK,GAAG,QAAQ,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS;IAC3D,SAAS,CAAC,MAAK;QACb,IAAI,CAAC,KAAK,EAAE;YACV,QAAQ,CACN,sBAAsB,EACtB,6DAA6D;AAC3D,gBAAA,wDAAwD,CAC3D;QACH;QACA,IAAI,KAAK,EAAE;YACT,QAAQ,CACN,iCAAiC,EACjC,mEAAmE;AACjE,gBAAA,0CAA0C,CAC7C;QACH;AACF,IAAA,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAElB,IAAA,MAAM,KAAK,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG;IACjC,MAAM,KAAK,GAAG,CAAC,IAAY,KAAK,CAACA,OAAK,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,GAAG,KAAK,IAAI,GAAG;;;IAIrE,MAAM,IAAI,GAAU,EAAE;IACtB,IAAI,QAAQ,EAAE;QACZ,IAAI,KAAK,GAAG,CAAC;AACb,QAAA,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;AAC9B,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC;AAC1D,YAAA,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;YAClD,KAAK,IAAI,MAAM;QACjB;IACF;SAAO;AACL,QAAA,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC;IACpD;AAEA,IAAA,MAAM,SAAS,GAAG,qBAAqB,CAAC,eAAe,EAAE;AACvD,QAAA,CAAC,CAAA,GAAA,EAAM,IAAI,CAAA,CAAE,GACX,CAAC,CAAC,IAAI,IAAK,sBAA4C,CAAC,QAAQ,CAAC,IAAI,CAAC;AACxE,QAAA,CAAC,MAAM,KAAK,CAAA,CAAE,GACZ,CAAC,CAAC,KAAK;AACN,YAAA,uBAA6C,CAAC,QAAQ,CAAC,KAAK,CAAC;QAChE,YAAY,EAAE,CAAC,CAAC,SAAS;QACzB,cAAc,EAAE,CAAC,CAAC,QAAQ;AAC3B,KAAA,CAAC;AACF,IAAA,MAAM,SAAS,GAAG,qBAAqB,CAAC,oBAAoB,CAAC;AAC7D,IAAA,MAAM,UAAU,GAAG,qBAAqB,CAAC,qBAAqB,CAAC;AAC/D,IAAA,MAAM,QAAQ,GAAG,qBAAqB,CAAC,mBAAmB,CAAC;AAC3D,IAAA,MAAM,UAAU,GAAG,qBAAqB,CAAC,qBAAqB,CAAC;;AAE/D,IAAA,MAAM,WAAW,GAAG,cAAc,EAAE;IAEpC,MAAM,SAAS,GAAG;AAChB,UAAE;AACE,YAAA,IAAI,EAAE,KAAK;AACX,YAAA,YAAY,EAAE;AACZ,gBAAA,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC;gBAC3B;qBACG,GAAG,CACF,CAAC,OAAO,EAAE,CAAC,KACT,CAAA,EAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA,CAAA,CAAG;qBAEpD,IAAI,CAAC,IAAI,CAAC;AACd;iBACE,MAAM,CAAC,OAAO;iBACd,IAAI,CAAC,IAAI,CAAC;AACd;AACH,UAAE;YACE,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,aAAa;YACvC,eAAe,EAAEA,OAAK,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;AAC5C,YAAA,eAAe,EAAE,CAAC;AAClB,YAAA,eAAe,EAAE,KAAK;AACtB,YAAA,YAAY,EAAE,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC;SAC1C;AAEL,IAAA,QACEC,IAAA,CAAA,KAAA,EAAA,EACE,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,UAAU,CAAC,SAAS,EAAE,kBAAkB,EAAE,SAAS,CAAC,EAAA,GAC3D,IAAI,EAAA,GACJ,SAAS,aAEbA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,SAAS,EAAE,OAAO,EAAC,aAAa,EAAA,aAAA,EAAa,MAAM,EAAA,QAAA,EAAA,CACjEC,GAAA,CAAA,QAAA,EAAA,EAAQ,SAAS,EAAE,UAAU,EAAE,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,CAAC,EAAC,IAAI,EAAA,CAAG,EACvD,IAAI,CAAC,GAAG,CACP,CAAC,GAAG,EAAE,CAAC,KACL,GAAG,CAAC,MAAM,GAAG,CAAC,KACZA,GAAA,CAAA,QAAA,EAAA,EAEE,SAAS,EAAE,UAAU,CACnB,QAAQ,EACR,GAAG,CAAC,KAAK;AACN,4BAAA,uBAA6C,CAAC,QAAQ,CACrD,GAAG,CAAC,KAAK,CACV;AACD,4BAAA,kBAAkB,CAAC,WAAW,EAAE,CAAA,GAAA,EAAM,GAAG,CAAC,KAAK,CAAA,CAAE,CAAC,CACrD,EACD,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAC,IAAI,EACN,UAAU,EAAE,GAAG,EACf,KAAK,EACH;4BACE,wBAAwB,EAAE,GAAG,CAAC,MAAM;4BACpC,uBAAuB,EAAE,GAAG,CAAC,KAAK;yBACZ,EAAA,EAjBrB,CAAC,CAmBN,CACH,CACJ,CAAA,EAAA,CACG,EACL,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI,KAI1CA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,UAAU,EAAA,aAAA,EAAc,MAAM,EAAA,QAAA,EAC3C,QAAQ,EAAA,CACL,CACP,CAAA,EAAA,CACG;AAEV,CAAC;AAGH,YAAY,CAAC,WAAW,GAAG,cAAc;;"}