@aglyn/shared-ui-jsx 1.0.0-beta.150 → 1.0.0-beta.152
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aglyn/shared-ui-jsx",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.152",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"homepage": "https://aglyn.com",
|
|
6
6
|
"repository": {
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"./package.json": "./package.json"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@aglyn/shared-data-mdi": "1.0.0-beta.
|
|
29
|
-
"@aglyn/shared-ui-theme": "1.0.0-beta.
|
|
30
|
-
"@aglyn/shared-util-tools": "1.0.0-beta.
|
|
31
|
-
"@aglyn/shared-util-vendor": "1.0.0-beta.
|
|
28
|
+
"@aglyn/shared-data-mdi": "1.0.0-beta.152",
|
|
29
|
+
"@aglyn/shared-ui-theme": "1.0.0-beta.152",
|
|
30
|
+
"@aglyn/shared-util-tools": "1.0.0-beta.152",
|
|
31
|
+
"@aglyn/shared-util-vendor": "1.0.0-beta.152",
|
|
32
32
|
"@mdi/js": "^7.4.47",
|
|
33
33
|
"@swc/helpers": "0.5.23",
|
|
34
34
|
"change-case": "^5.4.4",
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type ReactElement } from 'react';
|
|
2
|
+
export interface BlockedControlProps {
|
|
3
|
+
/**
|
|
4
|
+
* Whether the viewer's standing is RESOLVED and refused. Never true while
|
|
5
|
+
* a claim is still loading: rendering the refusal in that window flashes a
|
|
6
|
+
* disabled button at everybody, including the people who may use it.
|
|
7
|
+
*/
|
|
8
|
+
blocked: boolean;
|
|
9
|
+
/** Why, in one sentence. Shown on hover, and to a screen reader. */
|
|
10
|
+
reason: string;
|
|
11
|
+
/**
|
|
12
|
+
* A single control that accepts a `disabled` prop — MUI's Button,
|
|
13
|
+
* IconButton, Switch, TextField and friends all do.
|
|
14
|
+
*/
|
|
15
|
+
children: ReactElement<{
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Renders a control disabled with the reason attached, or passes it through
|
|
21
|
+
* untouched.
|
|
22
|
+
*
|
|
23
|
+
* DISABLED WITH THE REASON, NOT HIDDEN. Both are defensible and the choice is
|
|
24
|
+
* made here once rather than at every gate. Hiding leaves a reader unable to
|
|
25
|
+
* see that the capability exists at all, and the commonest support act is
|
|
26
|
+
* routing — "this needs someone with the super role" is an answer they can
|
|
27
|
+
* give in one message; "I see no such button" turns into an investigation of
|
|
28
|
+
* whether the feature shipped.
|
|
29
|
+
*
|
|
30
|
+
* ## Two details that are the whole reason this is shared
|
|
31
|
+
*
|
|
32
|
+
* The tooltip wraps a `span`, not the control: MUI does not fire pointer
|
|
33
|
+
* events on a disabled button, so a tooltip attached directly to one never
|
|
34
|
+
* appears — which would leave a dead button and no reason at all, the exact
|
|
35
|
+
* failure this exists to stop.
|
|
36
|
+
*
|
|
37
|
+
* And the reason lands on the span as a real `aria-label` and `title`, not
|
|
38
|
+
* only inside the Tooltip's popper. An explanation that appears only on
|
|
39
|
+
* hover says nothing to a screen reader and nothing on a touch device.
|
|
40
|
+
*
|
|
41
|
+
* Both were got right once and then copied; AGL-2113 is the precedent for
|
|
42
|
+
* what copies do — five quota readouts grew their own phrasing and stopped
|
|
43
|
+
* agreeing. THIS IS NOT A SECURITY BOUNDARY: the server refuses regardless
|
|
44
|
+
* of what rendered. It exists so a console stops promising what the server
|
|
45
|
+
* will refuse.
|
|
46
|
+
*/
|
|
47
|
+
export declare function BlockedControl({ blocked, reason, children }: BlockedControlProps): import("react").JSX.Element;
|
|
48
|
+
export declare namespace BlockedControl {
|
|
49
|
+
var displayName: string;
|
|
50
|
+
var aglyn: boolean;
|
|
51
|
+
}
|
|
52
|
+
export default BlockedControl;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
18
|
+
import { Box, Tooltip } from "@mui/material";
|
|
19
|
+
import { cloneElement, isValidElement } from "react";
|
|
20
|
+
/**
|
|
21
|
+
* Renders a control disabled with the reason attached, or passes it through
|
|
22
|
+
* untouched.
|
|
23
|
+
*
|
|
24
|
+
* DISABLED WITH THE REASON, NOT HIDDEN. Both are defensible and the choice is
|
|
25
|
+
* made here once rather than at every gate. Hiding leaves a reader unable to
|
|
26
|
+
* see that the capability exists at all, and the commonest support act is
|
|
27
|
+
* routing — "this needs someone with the super role" is an answer they can
|
|
28
|
+
* give in one message; "I see no such button" turns into an investigation of
|
|
29
|
+
* whether the feature shipped.
|
|
30
|
+
*
|
|
31
|
+
* ## Two details that are the whole reason this is shared
|
|
32
|
+
*
|
|
33
|
+
* The tooltip wraps a `span`, not the control: MUI does not fire pointer
|
|
34
|
+
* events on a disabled button, so a tooltip attached directly to one never
|
|
35
|
+
* appears — which would leave a dead button and no reason at all, the exact
|
|
36
|
+
* failure this exists to stop.
|
|
37
|
+
*
|
|
38
|
+
* And the reason lands on the span as a real `aria-label` and `title`, not
|
|
39
|
+
* only inside the Tooltip's popper. An explanation that appears only on
|
|
40
|
+
* hover says nothing to a screen reader and nothing on a touch device.
|
|
41
|
+
*
|
|
42
|
+
* Both were got right once and then copied; AGL-2113 is the precedent for
|
|
43
|
+
* what copies do — five quota readouts grew their own phrasing and stopped
|
|
44
|
+
* agreeing. THIS IS NOT A SECURITY BOUNDARY: the server refuses regardless
|
|
45
|
+
* of what rendered. It exists so a console stops promising what the server
|
|
46
|
+
* will refuse.
|
|
47
|
+
*/ export function BlockedControl({ blocked, reason, children }) {
|
|
48
|
+
if (!blocked || !/*#__PURE__*/ isValidElement(children)) return children;
|
|
49
|
+
return /*#__PURE__*/ _jsx(Tooltip, {
|
|
50
|
+
title: reason,
|
|
51
|
+
children: /*#__PURE__*/ _jsx(Box, {
|
|
52
|
+
component: "span",
|
|
53
|
+
"aria-label": reason,
|
|
54
|
+
title: reason,
|
|
55
|
+
sx: {
|
|
56
|
+
display: 'inline-flex'
|
|
57
|
+
},
|
|
58
|
+
children: /*#__PURE__*/ cloneElement(children, {
|
|
59
|
+
disabled: true
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
BlockedControl.displayName = 'BlockedControl';
|
|
65
|
+
BlockedControl.aglyn = true;
|
|
66
|
+
export default BlockedControl;
|
|
67
|
+
|
|
68
|
+
//# sourceMappingURL=blocked-control.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../libs/shared/ui/jsx/src/lib/components/blocked-control.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport { Box, Tooltip } from '@mui/material'\nimport { cloneElement, isValidElement, type ReactElement } from 'react'\n\nexport interface BlockedControlProps {\n /**\n * Whether the viewer's standing is RESOLVED and refused. Never true while\n * a claim is still loading: rendering the refusal in that window flashes a\n * disabled button at everybody, including the people who may use it.\n */\n blocked: boolean\n /** Why, in one sentence. Shown on hover, and to a screen reader. */\n reason: string\n /**\n * A single control that accepts a `disabled` prop — MUI's Button,\n * IconButton, Switch, TextField and friends all do.\n */\n children: ReactElement<{ disabled?: boolean }>\n}\n\n/**\n * Renders a control disabled with the reason attached, or passes it through\n * untouched.\n *\n * DISABLED WITH THE REASON, NOT HIDDEN. Both are defensible and the choice is\n * made here once rather than at every gate. Hiding leaves a reader unable to\n * see that the capability exists at all, and the commonest support act is\n * routing — \"this needs someone with the super role\" is an answer they can\n * give in one message; \"I see no such button\" turns into an investigation of\n * whether the feature shipped.\n *\n * ## Two details that are the whole reason this is shared\n *\n * The tooltip wraps a `span`, not the control: MUI does not fire pointer\n * events on a disabled button, so a tooltip attached directly to one never\n * appears — which would leave a dead button and no reason at all, the exact\n * failure this exists to stop.\n *\n * And the reason lands on the span as a real `aria-label` and `title`, not\n * only inside the Tooltip's popper. An explanation that appears only on\n * hover says nothing to a screen reader and nothing on a touch device.\n *\n * Both were got right once and then copied; AGL-2113 is the precedent for\n * what copies do — five quota readouts grew their own phrasing and stopped\n * agreeing. THIS IS NOT A SECURITY BOUNDARY: the server refuses regardless\n * of what rendered. It exists so a console stops promising what the server\n * will refuse.\n */\nexport function BlockedControl({ blocked, reason, children }: BlockedControlProps) {\n if (!blocked || !isValidElement(children)) return children\n return (\n <Tooltip title={reason}>\n <Box\n component=\"span\"\n aria-label={reason}\n title={reason}\n sx={{ display: 'inline-flex' }}\n >\n {cloneElement(children, { disabled: true })}\n </Box>\n </Tooltip>\n )\n}\n\nBlockedControl.displayName = 'BlockedControl'\nBlockedControl.aglyn = true\n\nexport default BlockedControl\n"],"names":["Box","Tooltip","cloneElement","isValidElement","BlockedControl","blocked","reason","children","title","component","aria-label","sx","display","disabled","displayName","aglyn"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,SAASA,GAAG,EAAEC,OAAO,QAAQ,gBAAe;AAC5C,SAASC,YAAY,EAAEC,cAAc,QAA2B,QAAO;AAkBvE;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GACD,OAAO,SAASC,eAAe,EAAEC,OAAO,EAAEC,MAAM,EAAEC,QAAQ,EAAuB;IAC/E,IAAI,CAACF,WAAW,eAACF,eAAeI,WAAW,OAAOA;IAClD,qBACE,KAACN;QAAQO,OAAOF;kBACd,cAAA,KAACN;YACCS,WAAU;YACVC,cAAYJ;YACZE,OAAOF;YACPK,IAAI;gBAAEC,SAAS;YAAc;sBAE5BV,cAAAA,aAAaK,UAAU;gBAAEM,UAAU;YAAK;;;AAIjD;AAEAT,eAAeU,WAAW,GAAG;AAC7BV,eAAeW,KAAK,GAAG;AAEvB,eAAeX,eAAc"}
|