@multiplatform.one/forms 7.88.5 → 7.88.6
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/cjs/Button/index.cjs +14 -4
- package/dist/cjs/Button/index.native.js +27 -4
- package/dist/cjs/Button/index.native.js.map +1 -1
- package/dist/cjs/FloatingPanel/pointAnchor.cjs +61 -17
- package/dist/cjs/FloatingPanel/pointAnchor.native.js +62 -17
- package/dist/cjs/FloatingPanel/pointAnchor.native.js.map +1 -1
- package/dist/esm/Button/index.mjs +14 -4
- package/dist/esm/Button/index.mjs.map +1 -1
- package/dist/esm/Button/index.native.js +27 -4
- package/dist/esm/Button/index.native.js.map +1 -1
- package/dist/esm/FloatingPanel/pointAnchor.mjs +61 -17
- package/dist/esm/FloatingPanel/pointAnchor.mjs.map +1 -1
- package/dist/esm/FloatingPanel/pointAnchor.native.js +62 -17
- package/dist/esm/FloatingPanel/pointAnchor.native.js.map +1 -1
- package/dist/jsx/Button/index.mjs +14 -4
- package/dist/jsx/Button/index.mjs.map +1 -1
- package/dist/jsx/Button/index.native.js +27 -4
- package/dist/jsx/Button/index.native.js.map +1 -1
- package/dist/jsx/FloatingPanel/pointAnchor.mjs +61 -17
- package/dist/jsx/FloatingPanel/pointAnchor.mjs.map +1 -1
- package/dist/jsx/FloatingPanel/pointAnchor.native.js +62 -17
- package/dist/jsx/FloatingPanel/pointAnchor.native.js.map +1 -1
- package/package.json +8 -8
- package/src/Button/Button.disabledWash.spec.tsx +229 -3
- package/src/Button/Button.nativeInk.spec.tsx +61 -1
- package/src/Button/index.tsx +28 -3
- package/src/FloatingPanel/FloatingPanel.stories.tsx +24 -22
- package/src/FloatingPanel/pointAnchor.ts +54 -34
- package/types/Button/index.d.ts.map +1 -1
- package/types/FloatingPanel/pointAnchor.d.ts.map +1 -1
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* house theme table of the scope that paints it.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import { cleanup, render, screen } from "@testing-library/react";
|
|
19
|
+
import { act, cleanup, render, screen } from "@testing-library/react";
|
|
20
20
|
import {
|
|
21
21
|
aaTextContrastRatio,
|
|
22
22
|
createDefaultThemeConfig,
|
|
@@ -24,11 +24,12 @@ import {
|
|
|
24
24
|
defaultAccentTheme,
|
|
25
25
|
defaultBaseTheme,
|
|
26
26
|
defaultBuilderOptions,
|
|
27
|
+
type Knobs,
|
|
27
28
|
measureContrast,
|
|
28
29
|
normalizeToHex,
|
|
29
30
|
Preset,
|
|
30
31
|
} from "@multiplatform.one/theme";
|
|
31
|
-
import type
|
|
32
|
+
import { type ReactElement, type ReactNode, useState } from "react";
|
|
32
33
|
import { TamaguiProvider, YStack } from "tamagui";
|
|
33
34
|
import { afterEach, describe, expect, it } from "vitest";
|
|
34
35
|
import { Button, type ButtonProps } from "./index";
|
|
@@ -118,7 +119,19 @@ function painted(el: Element, prefix: string, property: string, scheme: Scheme):
|
|
|
118
119
|
(c) => c.startsWith(prefix) && !/^_[a-z]+-0(hover|active|focus|press)/.test(c),
|
|
119
120
|
);
|
|
120
121
|
if (!cls) throw new Error(`${el.tagName} carries no ${prefix} class`);
|
|
121
|
-
|
|
122
|
+
const value = injectedRuleValue(cls, property);
|
|
123
|
+
const alias = value.match(/^var\((--[\w-]+)\)$/)?.[1];
|
|
124
|
+
const declarer = alias ? declaredOn(el, alias) : null;
|
|
125
|
+
return alias && declarer
|
|
126
|
+
? resolveInScope(declarer.style.getPropertyValue(alias).trim(), scheme, scopeOf(declarer))
|
|
127
|
+
: resolveInScope(value, scheme, scopeOf(el));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function declaredOn(el: Element, property: string): HTMLElement | null {
|
|
131
|
+
for (let node = el.parentElement; node; node = node.parentElement) {
|
|
132
|
+
if (node.style.getPropertyValue(property)) return node;
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
122
135
|
}
|
|
123
136
|
|
|
124
137
|
function opacityOf(el: Element): number {
|
|
@@ -204,3 +217,216 @@ describe("MPO-433 LC-40: keepLabel keeps the disabled label ≥ 4.5:1 on its own
|
|
|
204
217
|
}
|
|
205
218
|
}
|
|
206
219
|
});
|
|
220
|
+
|
|
221
|
+
let flipScheme: (scheme: Scheme) => void = () => {};
|
|
222
|
+
|
|
223
|
+
function SchemeRoot({ initial, children }: { initial: Scheme; children: ReactNode }) {
|
|
224
|
+
const [scheme, setScheme] = useState<Scheme>(initial);
|
|
225
|
+
flipScheme = setScheme;
|
|
226
|
+
return (
|
|
227
|
+
<TamaguiProvider config={houseConfig.tamagui} defaultTheme={scheme} disableInjectCSS>
|
|
228
|
+
{children}
|
|
229
|
+
</TamaguiProvider>
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function schemeOf(el: Element): Scheme | null {
|
|
234
|
+
for (let node = el.parentElement; node; node = node.parentElement) {
|
|
235
|
+
if (node.classList.contains("t_dark")) return "dark";
|
|
236
|
+
if (node.classList.contains("t_light")) return "light";
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function disabledPaint(scheme: Scheme) {
|
|
242
|
+
const label = screen.getByText("Disabled");
|
|
243
|
+
const frame = label.closest("[role=button]") as Element;
|
|
244
|
+
return {
|
|
245
|
+
scheme: schemeOf(frame),
|
|
246
|
+
fill: painted(frame, "_bg-", "background-color", scheme),
|
|
247
|
+
border: painted(frame, "_btc-", "border-top-color", scheme),
|
|
248
|
+
ink: painted(label, "_col-", "color", scheme),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const KNOB_SPACE = {
|
|
253
|
+
fillStyle: ["filled", "outlined"],
|
|
254
|
+
borderRadius: ["none", "small", "medium", "large", "full"],
|
|
255
|
+
borderWidth: ["none", "small", "medium", "large"],
|
|
256
|
+
elevation: ["none", "small", "medium", "large"],
|
|
257
|
+
textAccent: ["low", "medium", "high"],
|
|
258
|
+
} as const;
|
|
259
|
+
|
|
260
|
+
function knobFuzz(seed: number, count: number): Partial<Knobs>[] {
|
|
261
|
+
let state = seed;
|
|
262
|
+
const next = () => {
|
|
263
|
+
state = (state + 0x6d2b79f5) | 0;
|
|
264
|
+
let t = Math.imul(state ^ (state >>> 15), 1 | state);
|
|
265
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
266
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
267
|
+
};
|
|
268
|
+
return Array.from(
|
|
269
|
+
{ length: count },
|
|
270
|
+
() =>
|
|
271
|
+
({
|
|
272
|
+
disabledStyle: "keepLabel",
|
|
273
|
+
...Object.fromEntries(
|
|
274
|
+
Object.entries(KNOB_SPACE).map(([knob, values]) => [
|
|
275
|
+
knob,
|
|
276
|
+
values[Math.floor(next() * values.length)],
|
|
277
|
+
]),
|
|
278
|
+
),
|
|
279
|
+
}) as Partial<Knobs>,
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const KNOB_COMBOS: Partial<Knobs>[] = [
|
|
284
|
+
{ disabledStyle: "keepLabel" },
|
|
285
|
+
{ disabledStyle: "dimWhole" },
|
|
286
|
+
...knobFuzz(9578, 3),
|
|
287
|
+
];
|
|
288
|
+
|
|
289
|
+
const SOLID_PALETTE = VARIANTS.filter((v) => v.name === "accent" || v.name === 'theme="accent"');
|
|
290
|
+
|
|
291
|
+
function swapSchemeClass(from: Scheme, to: Scheme) {
|
|
292
|
+
for (const el of Array.from(document.querySelectorAll(`.t_${from}`))) {
|
|
293
|
+
el.classList.replace(`t_${from}`, `t_${to}`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
describe("FZ-9578 LC-40: a disabled solid-palette Button follows a scheme flip with no prop change", () => {
|
|
298
|
+
const FLIPS = [
|
|
299
|
+
["light", "dark"],
|
|
300
|
+
["dark", "light"],
|
|
301
|
+
] as const;
|
|
302
|
+
for (const [from, to] of FLIPS) {
|
|
303
|
+
for (const variant of SOLID_PALETTE) {
|
|
304
|
+
for (const knobs of KNOB_COMBOS) {
|
|
305
|
+
const button = (
|
|
306
|
+
<Preset overrides={knobs}>
|
|
307
|
+
<YStack backgroundColor="$background">
|
|
308
|
+
<Button {...variant.props} disabled>
|
|
309
|
+
Disabled
|
|
310
|
+
</Button>
|
|
311
|
+
</YStack>
|
|
312
|
+
</Preset>
|
|
313
|
+
);
|
|
314
|
+
const label = `${from} -> ${to} ${variant.name} ${JSON.stringify(knobs)}`;
|
|
315
|
+
|
|
316
|
+
it(`${label}: a flip that never re-renders it paints what a fresh ${to} mount paints`, () => {
|
|
317
|
+
render(<SchemeRoot initial={to}>{button}</SchemeRoot>);
|
|
318
|
+
const fresh = disabledPaint(to);
|
|
319
|
+
cleanup();
|
|
320
|
+
render(<SchemeRoot initial={from}>{button}</SchemeRoot>);
|
|
321
|
+
swapSchemeClass(from, to);
|
|
322
|
+
try {
|
|
323
|
+
expect(disabledPaint(to)).toEqual(fresh);
|
|
324
|
+
} finally {
|
|
325
|
+
swapSchemeClass(to, from);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it(`${label}: a provider flip paints what a fresh ${to} mount paints`, () => {
|
|
330
|
+
render(<SchemeRoot initial={to}>{button}</SchemeRoot>);
|
|
331
|
+
const fresh = disabledPaint(to);
|
|
332
|
+
cleanup();
|
|
333
|
+
render(<SchemeRoot initial={from}>{button}</SchemeRoot>);
|
|
334
|
+
act(() => flipScheme(to));
|
|
335
|
+
expect(disabledPaint(to)).toEqual(fresh);
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
describe("FZ-9578: a focused solid-palette Button keeps its node and focus when it turns disabled", () => {
|
|
343
|
+
for (const variant of SOLID_PALETTE) {
|
|
344
|
+
it(variant.name, () => {
|
|
345
|
+
const view = (disabled: boolean) => (
|
|
346
|
+
<TamaguiProvider config={houseConfig.tamagui} defaultTheme="light" disableInjectCSS>
|
|
347
|
+
<Preset overrides={{ disabledStyle: "keepLabel" }}>
|
|
348
|
+
<YStack backgroundColor="$background">
|
|
349
|
+
<Button {...variant.props} disabled={disabled}>
|
|
350
|
+
Go
|
|
351
|
+
</Button>
|
|
352
|
+
</YStack>
|
|
353
|
+
</Preset>
|
|
354
|
+
</TamaguiProvider>
|
|
355
|
+
);
|
|
356
|
+
const { rerender } = render(view(false));
|
|
357
|
+
const frame = screen.getByText("Go").closest("[role=button]") as HTMLElement;
|
|
358
|
+
frame.focus();
|
|
359
|
+
rerender(view(true));
|
|
360
|
+
expect(screen.getByText("Go").closest("[role=button]")).toBe(frame);
|
|
361
|
+
expect(document.activeElement).toBe(frame);
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
const WASH_KNOBS: Partial<Knobs> = {
|
|
367
|
+
disabledStyle: "keepLabel",
|
|
368
|
+
fillStyle: "filled",
|
|
369
|
+
borderWidth: "medium",
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
function washedButton(props: Partial<ButtonProps>, disabled: boolean, text: string) {
|
|
373
|
+
return (
|
|
374
|
+
<Preset overrides={WASH_KNOBS}>
|
|
375
|
+
<YStack backgroundColor="$background">
|
|
376
|
+
<Button {...props} disabled={disabled}>
|
|
377
|
+
{text}
|
|
378
|
+
</Button>
|
|
379
|
+
</YStack>
|
|
380
|
+
</Preset>
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function hostRecipe(scheme: Scheme) {
|
|
385
|
+
const host = houseThemes[scheme] ?? {};
|
|
386
|
+
return { scheme, fill: host.color3, border: host.color6, ink: host.color11 };
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
describe("FZ-9578 LC-40: a disabled solid-palette Button washes on the host scope's $color3, $color6 and $color11", () => {
|
|
390
|
+
for (const scheme of SCHEMES) {
|
|
391
|
+
const from: Scheme = scheme === "light" ? "dark" : "light";
|
|
392
|
+
for (const variant of SOLID_PALETTE) {
|
|
393
|
+
it(`${scheme} ${variant.name}: a fresh mount`, () => {
|
|
394
|
+
render(
|
|
395
|
+
<SchemeRoot initial={scheme}>{washedButton(variant.props, true, "Disabled")}</SchemeRoot>,
|
|
396
|
+
);
|
|
397
|
+
expect(hostRecipe(scheme).fill).toMatch(/^#|^rgb|^hsl/);
|
|
398
|
+
expect(disabledPaint(scheme)).toEqual(hostRecipe(scheme));
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it(`${from} -> ${scheme} ${variant.name}: a flip that never re-renders it`, () => {
|
|
402
|
+
render(
|
|
403
|
+
<SchemeRoot initial={from}>{washedButton(variant.props, true, "Disabled")}</SchemeRoot>,
|
|
404
|
+
);
|
|
405
|
+
swapSchemeClass(from, scheme);
|
|
406
|
+
try {
|
|
407
|
+
expect(disabledPaint(scheme)).toEqual(hostRecipe(scheme));
|
|
408
|
+
} finally {
|
|
409
|
+
swapSchemeClass(scheme, from);
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
describe("FZ-9578: the span that declares the host wash aliases is display: contents", () => {
|
|
417
|
+
for (const scheme of SCHEMES) {
|
|
418
|
+
for (const variant of SOLID_PALETTE) {
|
|
419
|
+
for (const disabled of [false, true]) {
|
|
420
|
+
it(`${scheme} ${variant.name} ${disabled ? "disabled" : "enabled"}`, () => {
|
|
421
|
+
render(
|
|
422
|
+
<SchemeRoot initial={scheme}>{washedButton(variant.props, disabled, "Go")}</SchemeRoot>,
|
|
423
|
+
);
|
|
424
|
+
const frame = screen.getByText("Go").closest("[role=button]") as Element;
|
|
425
|
+
const span = declaredOn(frame, "--mp-host-color3");
|
|
426
|
+
expect(span?.tagName).toBe("SPAN");
|
|
427
|
+
expect((span as HTMLElement).style.display).toBe("contents");
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cleanup, render, screen } from "@testing-library/react";
|
|
2
|
-
import { createDefaultThemeConfig } from "@multiplatform.one/theme";
|
|
2
|
+
import { createDefaultThemeConfig, Preset } from "@multiplatform.one/theme";
|
|
3
3
|
import { memo } from "react";
|
|
4
4
|
import { getVariableValue, TamaguiProvider, useTheme } from "tamagui";
|
|
5
5
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
@@ -114,3 +114,63 @@ describe("native Button icon ink", () => {
|
|
|
114
114
|
expect(screen.getByTestId("icon").dataset.color).toBe("");
|
|
115
115
|
});
|
|
116
116
|
});
|
|
117
|
+
|
|
118
|
+
function HostProbe() {
|
|
119
|
+
const theme = useTheme();
|
|
120
|
+
return (
|
|
121
|
+
<span
|
|
122
|
+
data-testid="host"
|
|
123
|
+
data-wash={String(getVariableValue(theme.color3))}
|
|
124
|
+
data-ink={String(getVariableValue(theme.color11))}
|
|
125
|
+
/>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function injectedRuleValue(className: string, property: string): string | undefined {
|
|
130
|
+
for (const sheet of Array.from(document.styleSheets)) {
|
|
131
|
+
for (const rule of Array.from(sheet.cssRules)) {
|
|
132
|
+
const style = (rule as CSSStyleRule).style;
|
|
133
|
+
if (!(rule as CSSStyleRule).selectorText?.endsWith(`.${className}`) || !style) continue;
|
|
134
|
+
const value = style.getPropertyValue(property);
|
|
135
|
+
if (value) return value.trim();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function frameFill(text: string): string | undefined {
|
|
142
|
+
const frame = screen.getByText(text).closest("[role=button]") as Element;
|
|
143
|
+
const cls = Array.from(frame.classList).find(
|
|
144
|
+
(c) => c.startsWith("_bg-") && !/^_bg-0(hover|active|focus|press)/.test(c),
|
|
145
|
+
);
|
|
146
|
+
return cls ? injectedRuleValue(cls, "background-color") : undefined;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
describe("FZ-9578: a native disabled accent Button keeps the host scope's literal wash", () => {
|
|
150
|
+
it.each(["light", "dark"] as const)(
|
|
151
|
+
"%s paints the host $color3 and $color11 as literals, never a CSS variable",
|
|
152
|
+
(scheme) => {
|
|
153
|
+
render(
|
|
154
|
+
<TamaguiProvider config={config.tamagui} defaultTheme={scheme} disableInjectCSS>
|
|
155
|
+
<HostProbe />
|
|
156
|
+
<Preset overrides={{ disabledStyle: "keepLabel", fillStyle: "filled" }}>
|
|
157
|
+
<Button accent disabled icon={IconProbe}>
|
|
158
|
+
Save
|
|
159
|
+
</Button>
|
|
160
|
+
<Button theme="accent" disabled icon={IconProbe}>
|
|
161
|
+
Send
|
|
162
|
+
</Button>
|
|
163
|
+
</Preset>
|
|
164
|
+
</TamaguiProvider>,
|
|
165
|
+
);
|
|
166
|
+
const host = screen.getByTestId("host").dataset;
|
|
167
|
+
expect(host.ink).toMatch(/^#|^rgb|^hsl/);
|
|
168
|
+
for (const icon of screen.getAllByTestId("icon")) {
|
|
169
|
+
expect(icon.dataset.color).toBe(host.ink);
|
|
170
|
+
}
|
|
171
|
+
for (const text of ["Save", "Send"]) {
|
|
172
|
+
expect(frameFill(text)).toBe(host.wash);
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
);
|
|
176
|
+
});
|
package/src/Button/index.tsx
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
useId,
|
|
12
12
|
useState,
|
|
13
13
|
type ComponentType,
|
|
14
|
+
type CSSProperties,
|
|
14
15
|
type ReactNode,
|
|
15
16
|
} from "react";
|
|
16
17
|
import {
|
|
@@ -789,6 +790,18 @@ export function Button({
|
|
|
789
790
|
: value,
|
|
790
791
|
]),
|
|
791
792
|
) as T;
|
|
793
|
+
const hostWashVar = (token: string) => `--mp-host-${token}`;
|
|
794
|
+
const hostWash = <T extends object>(fragment: T): T =>
|
|
795
|
+
isWeb
|
|
796
|
+
? (Object.fromEntries(
|
|
797
|
+
Object.entries(fragment).map(([key, value]) => [
|
|
798
|
+
key,
|
|
799
|
+
typeof value === "string" && value.startsWith("$")
|
|
800
|
+
? `var(${hostWashVar(value.slice(1))})`
|
|
801
|
+
: value,
|
|
802
|
+
]),
|
|
803
|
+
) as T)
|
|
804
|
+
: hostScoped(fragment);
|
|
792
805
|
// LC-40 / MPO-433: a solid-palette theme has no wash tier, so the wash and
|
|
793
806
|
// its ink come from the host scope. Solid-intent ramps keep their own wash,
|
|
794
807
|
// where `$color11` misses 4.5:1 (light warning 4.48, success 4.27) and the
|
|
@@ -809,14 +822,14 @@ export function Button({
|
|
|
809
822
|
borderColor: tierDisabled.borderColor,
|
|
810
823
|
}
|
|
811
824
|
: washOnHost
|
|
812
|
-
?
|
|
825
|
+
? hostWash(disabledState.surfaceKnobProps)
|
|
813
826
|
: disabledState.surfaceKnobProps;
|
|
814
827
|
const disabledText: { color?: string } = frameless
|
|
815
828
|
? {}
|
|
816
829
|
: tierDisabled
|
|
817
830
|
? { ...disabledState.textKnobProps, color: tierDisabled.color }
|
|
818
831
|
: washOnHost
|
|
819
|
-
?
|
|
832
|
+
? hostWash(disabledState.textKnobProps)
|
|
820
833
|
: activeThemeName &&
|
|
821
834
|
solidButtonIntents.has(activeThemeName) &&
|
|
822
835
|
disabledState.textKnobProps.color
|
|
@@ -1447,9 +1460,21 @@ export function Button({
|
|
|
1447
1460
|
) : (
|
|
1448
1461
|
buttonElement
|
|
1449
1462
|
);
|
|
1463
|
+
const hostWashScope = Object.fromEntries(
|
|
1464
|
+
[disabledState.surfaceKnobProps, disabledState.textKnobProps]
|
|
1465
|
+
.flatMap((fragment) => Object.values(fragment))
|
|
1466
|
+
.filter((value): value is string => typeof value === "string" && value.startsWith("$"))
|
|
1467
|
+
.map((value) => [hostWashVar(value.slice(1)), `var(--${value.slice(1)})`]),
|
|
1468
|
+
);
|
|
1469
|
+
const hostedButton =
|
|
1470
|
+
isWeb && activeThemeName && solidPaletteThemes.has(activeThemeName) ? (
|
|
1471
|
+
<span style={{ display: "contents", ...hostWashScope } as CSSProperties}>{intentButton}</span>
|
|
1472
|
+
) : (
|
|
1473
|
+
intentButton
|
|
1474
|
+
);
|
|
1450
1475
|
// The media plate reads the same over any picture in either scheme: a dark
|
|
1451
1476
|
// material with a light glyph.
|
|
1452
|
-
const themedButton = mediaPlate ? <Theme name="dark">{
|
|
1477
|
+
const themedButton = mediaPlate ? <Theme name="dark">{hostedButton}</Theme> : hostedButton;
|
|
1453
1478
|
|
|
1454
1479
|
// DG-ST-03 explain affordance: visible reason adjacent to the control —
|
|
1455
1480
|
// discoverable by pointer, touch, keyboard, and SR (aria-describedby)
|
|
@@ -274,6 +274,29 @@ export const InsideScrollView: Story = {
|
|
|
274
274
|
),
|
|
275
275
|
};
|
|
276
276
|
|
|
277
|
+
function EndEdgeCustomFirstRowDemo() {
|
|
278
|
+
const [open, setOpen] = useState(true);
|
|
279
|
+
return (
|
|
280
|
+
<XStack width="100%" padding="$4" justifyContent="flex-end">
|
|
281
|
+
<FloatingPanel
|
|
282
|
+
open={open}
|
|
283
|
+
onOpenChange={setOpen}
|
|
284
|
+
anchorMode="cover-trigger"
|
|
285
|
+
triggerEcho={false}
|
|
286
|
+
coverAlign="start"
|
|
287
|
+
widthMode="fit-content"
|
|
288
|
+
triggerSizing="content"
|
|
289
|
+
trigger={<Button aria-label="Appearance">◐</Button>}
|
|
290
|
+
>
|
|
291
|
+
<YStack padding="$3" gap="$2" width={240}>
|
|
292
|
+
<Text>Appearance</Text>
|
|
293
|
+
<Paragraph color={formCommonColors.muted}>System, light or dark.</Paragraph>
|
|
294
|
+
</YStack>
|
|
295
|
+
</FloatingPanel>
|
|
296
|
+
</XStack>
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
|
|
277
300
|
/**
|
|
278
301
|
* LC-139 (FZ-9053, FZ-9258): a panel whose first row is its own, not an echo,
|
|
279
302
|
* opened from a button at the page's end edge on a desktop-width page. It
|
|
@@ -281,26 +304,5 @@ export const InsideScrollView: Story = {
|
|
|
281
304
|
*/
|
|
282
305
|
export const EndEdgeCustomFirstRow: Story = {
|
|
283
306
|
name: "End edge, custom first row",
|
|
284
|
-
render: () =>
|
|
285
|
-
const [open, setOpen] = useState(true);
|
|
286
|
-
return (
|
|
287
|
-
<XStack width="100%" padding="$4" justifyContent="flex-end">
|
|
288
|
-
<FloatingPanel
|
|
289
|
-
open={open}
|
|
290
|
-
onOpenChange={setOpen}
|
|
291
|
-
anchorMode="cover-trigger"
|
|
292
|
-
triggerEcho={false}
|
|
293
|
-
coverAlign="start"
|
|
294
|
-
widthMode="fit-content"
|
|
295
|
-
triggerSizing="content"
|
|
296
|
-
trigger={<Button aria-label="Appearance">◐</Button>}
|
|
297
|
-
>
|
|
298
|
-
<YStack padding="$3" gap="$2" width={240}>
|
|
299
|
-
<Text>Appearance</Text>
|
|
300
|
-
<Paragraph color={formCommonColors.muted}>System, light or dark.</Paragraph>
|
|
301
|
-
</YStack>
|
|
302
|
-
</FloatingPanel>
|
|
303
|
-
</XStack>
|
|
304
|
-
);
|
|
305
|
-
},
|
|
307
|
+
render: () => <EndEdgeCustomFirstRowDemo />,
|
|
306
308
|
};
|
|
@@ -142,6 +142,48 @@ export interface TriggerPlacement {
|
|
|
142
142
|
up: boolean;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
function placeAcross(
|
|
146
|
+
trigger: TriggerRect,
|
|
147
|
+
width: number,
|
|
148
|
+
bounds: PanelBounds,
|
|
149
|
+
{ rtl, align, echo }: Readonly<{ rtl: boolean; align: "start" | "auto"; echo: boolean }>,
|
|
150
|
+
): { width: number; left: number; wantLeft: number; end: boolean } {
|
|
151
|
+
const room = Math.max(0, bounds.right - bounds.left);
|
|
152
|
+
const w = Math.min(Math.max(width, trigger.width), room);
|
|
153
|
+
const startLeft = rtl ? trigger.x + trigger.width - w : trigger.x;
|
|
154
|
+
const endLeft = rtl ? trigger.x : trigger.x + trigger.width - w;
|
|
155
|
+
// Only the free edge has to clear the padded bounds: the aligned edge is
|
|
156
|
+
// the trigger's own, so a bar button inside the margin keeps its corner.
|
|
157
|
+
const startFree = rtl ? startLeft >= bounds.left : startLeft + w <= bounds.right;
|
|
158
|
+
const endFree = rtl ? endLeft + w <= bounds.right : endLeft >= bounds.left;
|
|
159
|
+
const auto = align === "auto";
|
|
160
|
+
const end = auto && !startFree && endFree;
|
|
161
|
+
const wantLeft = end ? endLeft : startLeft;
|
|
162
|
+
if (auto && (end || startFree)) return { width: w, left: wantLeft, wantLeft, end };
|
|
163
|
+
// FZ-8414: an echoed menu that cannot open from its start corner lines its
|
|
164
|
+
// end edge up with the trigger's, the UIMenu pull-down, so it never runs
|
|
165
|
+
// past the content margin the trigger sits inside.
|
|
166
|
+
if (echo && !startFree && endFree) return { width: w, left: endLeft, wantLeft, end };
|
|
167
|
+
const left = Math.max(bounds.left, Math.min(wantLeft, bounds.right - w));
|
|
168
|
+
return { width: w, left, wantLeft, end };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function placePinned(
|
|
172
|
+
trigger: TriggerRect,
|
|
173
|
+
height: number,
|
|
174
|
+
bounds: PanelBounds,
|
|
175
|
+
): { top: number; maxHeight: number; up: boolean } {
|
|
176
|
+
const triggerBottom = trigger.y + trigger.height;
|
|
177
|
+
const below = Math.max(0, bounds.bottom - trigger.y);
|
|
178
|
+
const above = Math.max(0, triggerBottom - bounds.top);
|
|
179
|
+
const up = height > below && above > below;
|
|
180
|
+
return {
|
|
181
|
+
top: up ? Math.max(bounds.top, triggerBottom - height) : trigger.y,
|
|
182
|
+
maxHeight: up ? above : below,
|
|
183
|
+
up,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
145
187
|
/**
|
|
146
188
|
* A menu opened over its trigger (LC-112) where no bottom sheet may take it:
|
|
147
189
|
* on native, and inside another overlay (FZ-7830). Its top start corner sits
|
|
@@ -184,41 +226,19 @@ export function placeOverTrigger({
|
|
|
184
226
|
*/
|
|
185
227
|
echo?: boolean;
|
|
186
228
|
}): TriggerPlacement {
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const wantLeft = end ? endLeft : startLeft;
|
|
198
|
-
const keep = auto && (end || startFree);
|
|
199
|
-
// FZ-8414: an echoed menu that cannot open from its start corner lines its
|
|
200
|
-
// end edge up with the trigger's, the UIMenu pull-down, so it never runs
|
|
201
|
-
// past the content margin the trigger sits inside.
|
|
202
|
-
const left = keep
|
|
203
|
-
? wantLeft
|
|
204
|
-
: echo && !startFree && endFree
|
|
205
|
-
? endLeft
|
|
206
|
-
: Math.max(bounds.left, Math.min(wantLeft, bounds.right - w));
|
|
229
|
+
const {
|
|
230
|
+
width: w,
|
|
231
|
+
left,
|
|
232
|
+
wantLeft,
|
|
233
|
+
end,
|
|
234
|
+
} = placeAcross(trigger, width, bounds, {
|
|
235
|
+
rtl,
|
|
236
|
+
align,
|
|
237
|
+
echo,
|
|
238
|
+
});
|
|
207
239
|
if (pinned) {
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
const above = Math.max(0, triggerBottom - bounds.top);
|
|
211
|
-
const up = height > below && above > below;
|
|
212
|
-
const top = up ? Math.max(bounds.top, triggerBottom - height) : trigger.y;
|
|
213
|
-
return {
|
|
214
|
-
left,
|
|
215
|
-
top,
|
|
216
|
-
width: w,
|
|
217
|
-
maxHeight: up ? above : below,
|
|
218
|
-
shifted: left !== wantLeft,
|
|
219
|
-
end,
|
|
220
|
-
up,
|
|
221
|
-
};
|
|
240
|
+
const { top, maxHeight, up } = placePinned(trigger, height, bounds);
|
|
241
|
+
return { left, top, width: w, maxHeight, shifted: left !== wantLeft, end, up };
|
|
222
242
|
}
|
|
223
243
|
const h = Math.min(height, Math.max(0, bounds.bottom - bounds.top));
|
|
224
244
|
const top = Math.max(bounds.top, Math.min(trigger.y, bounds.bottom - h));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Button/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EASL,KAAK,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Button/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pointAnchor.d.ts","sourceRoot":"","sources":["../../src/FloatingPanel/pointAnchor.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,WAAW,EACnB,GAAG,UAAQ,GACV;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAOrC;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAC1B,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,EACnB,GAAG,GAAE,MAA2B,GAC/B,OAAO,CAMT;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,MAAM,EACN,MAAM,EACN,GAAwB,EACxB,GAAW,GACZ,EAAE;IACD,KAAK,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,GAAG,cAAc,CASjB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,oBAAoB,EAC3B,SAAS,EAAE,cAAc,GAAG,IAAI,EAChC,GAAG,UAAQ,GACV,UAAU,GAAG,IAAI,CAOnB;AAED,MAAM,WAAW,cAAc;IAC7B,qBAAqB,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1E;AAED,4EAA4E;AAC5E,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,UAAQ,GAAG,UAAU,CAGvF;AAED,kFAAkF;AAClF,MAAM,WAAW,WAAW;IAC1B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,OAAO,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,GAAG,EAAE,OAAO,CAAC;IACb,qEAAqE;IACrE,EAAE,EAAE,OAAO,CAAC;CACb;
|
|
1
|
+
{"version":3,"file":"pointAnchor.d.ts","sourceRoot":"","sources":["../../src/FloatingPanel/pointAnchor.ts"],"names":[],"mappings":"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"}
|