@kanso-labs/react-native-kanso-ui 0.0.0-stage → 0.1.1
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/LICENSE.md +20 -0
- package/README.md +205 -2
- package/dist/button/index.d.ts +56 -0
- package/dist/button/index.js +169 -0
- package/dist/button/index.js.map +1 -0
- package/dist/button/palettes.js +47 -0
- package/dist/button/palettes.js.map +1 -0
- package/dist/chip/index.js +194 -0
- package/dist/chip/index.js.map +1 -0
- package/dist/chip/styles.js +36 -0
- package/dist/chip/styles.js.map +1 -0
- package/dist/clipboard/index.js +58 -0
- package/dist/clipboard/index.js.map +1 -0
- package/dist/components/avatar/index.d.ts +82 -0
- package/dist/components/avatar/index.js +62 -0
- package/dist/components/avatar/index.js.map +1 -0
- package/dist/components/button/index.d.ts +87 -0
- package/dist/components/button/index.js +377 -0
- package/dist/components/button/index.js.map +1 -0
- package/dist/components/card/index.d.ts +78 -0
- package/dist/components/card/index.js +315 -0
- package/dist/components/card/index.js.map +1 -0
- package/dist/components/checkbox/index.d.ts +76 -0
- package/dist/components/checkbox/index.js +360 -0
- package/dist/components/checkbox/index.js.map +1 -0
- package/dist/components/chip/index.d.ts +84 -0
- package/dist/components/chip/index.js +257 -0
- package/dist/components/chip/index.js.map +1 -0
- package/dist/components/chip-group/index.d.ts +143 -0
- package/dist/components/chip-group/index.js +669 -0
- package/dist/components/chip-group/index.js.map +1 -0
- package/dist/components/copy-field/index.d.ts +60 -0
- package/dist/components/copy-field/index.js +277 -0
- package/dist/components/copy-field/index.js.map +1 -0
- package/dist/components/currency/index.d.ts +69 -0
- package/dist/components/currency/index.js +162 -0
- package/dist/components/currency/index.js.map +1 -0
- package/dist/components/form/index.d.ts +84 -0
- package/dist/components/form/index.js +95 -0
- package/dist/components/form/index.js.map +1 -0
- package/dist/components/icon-button/index.d.ts +68 -0
- package/dist/components/icon-button/index.js +289 -0
- package/dist/components/icon-button/index.js.map +1 -0
- package/dist/components/link/index.d.ts +59 -0
- package/dist/components/link/index.js +191 -0
- package/dist/components/link/index.js.map +1 -0
- package/dist/components/number-field/index.d.ts +151 -0
- package/dist/components/number-field/index.js +832 -0
- package/dist/components/number-field/index.js.map +1 -0
- package/dist/components/product-icon/index.d.ts +70 -0
- package/dist/components/product-icon/index.js +60 -0
- package/dist/components/product-icon/index.js.map +1 -0
- package/dist/components/radio-group/index.d.ts +105 -0
- package/dist/components/radio-group/index.js +597 -0
- package/dist/components/radio-group/index.js.map +1 -0
- package/dist/components/search-field/index.d.ts +98 -0
- package/dist/components/search-field/index.js +521 -0
- package/dist/components/search-field/index.js.map +1 -0
- package/dist/components/segmented-button/index.d.ts +113 -0
- package/dist/components/segmented-button/index.js +937 -0
- package/dist/components/segmented-button/index.js.map +1 -0
- package/dist/components/separator/index.d.ts +45 -0
- package/dist/components/separator/index.js +109 -0
- package/dist/components/separator/index.js.map +1 -0
- package/dist/components/stack/index.d.ts +70 -0
- package/dist/components/stack/index.js +107 -0
- package/dist/components/stack/index.js.map +1 -0
- package/dist/components/switch/index.d.ts +76 -0
- package/dist/components/switch/index.js +591 -0
- package/dist/components/switch/index.js.map +1 -0
- package/dist/components/text/index.d.ts +44 -0
- package/dist/components/text/index.js +78 -0
- package/dist/components/text/index.js.map +1 -0
- package/dist/components/text-field/index.d.ts +146 -0
- package/dist/components/text-field/index.js +228 -0
- package/dist/components/text-field/index.js.map +1 -0
- package/dist/control/index.js +117 -0
- package/dist/control/index.js.map +1 -0
- package/dist/control/styles.js +36 -0
- package/dist/control/styles.js.map +1 -0
- package/dist/field/index.d.ts +13 -0
- package/dist/field/index.js +1007 -0
- package/dist/field/index.js.map +1 -0
- package/dist/field/styles.js +131 -0
- package/dist/field/styles.js.map +1 -0
- package/dist/form/index.d.ts +24 -0
- package/dist/form/index.js +209 -0
- package/dist/form/index.js.map +1 -0
- package/dist/glyphs/icon-style.d.ts +25 -0
- package/dist/glyphs/icon-style.js +22 -0
- package/dist/glyphs/icon-style.js.map +1 -0
- package/dist/glyphs/index.js +170 -0
- package/dist/glyphs/index.js.map +1 -0
- package/dist/glyphs/styles.js +7 -0
- package/dist/glyphs/styles.js.map +1 -0
- package/dist/hooks/useWindowSizeClass.d.ts +25 -0
- package/dist/hooks/useWindowSizeClass.js +39 -0
- package/dist/hooks/useWindowSizeClass.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +27 -0
- package/dist/mark/image.js +61 -0
- package/dist/mark/image.js.map +1 -0
- package/dist/mark/index.d.ts +9 -0
- package/dist/mark/index.js +234 -0
- package/dist/mark/index.js.map +1 -0
- package/dist/mark/initials.js +65 -0
- package/dist/mark/initials.js.map +1 -0
- package/dist/mark/styles.d.ts +1 -0
- package/dist/mark/styles.js +73 -0
- package/dist/mark/styles.js.map +1 -0
- package/dist/number/parser.js +321 -0
- package/dist/number/parser.js.map +1 -0
- package/dist/number/state.js +235 -0
- package/dist/number/state.js.map +1 -0
- package/dist/overlay/host.js +111 -0
- package/dist/overlay/host.js.map +1 -0
- package/dist/press/index.js +350 -0
- package/dist/press/index.js.map +1 -0
- package/dist/press/styles.js +31 -0
- package/dist/press/styles.js.map +1 -0
- package/dist/router/index.d.ts +28 -0
- package/dist/router/index.js +82 -0
- package/dist/router/index.js.map +1 -0
- package/dist/theme/color.js +25 -0
- package/dist/theme/color.js.map +1 -0
- package/dist/theme/resolve.d.ts +6 -0
- package/dist/theme/resolve.js +310 -0
- package/dist/theme/resolve.js.map +1 -0
- package/dist/theme/scope.d.ts +42 -0
- package/dist/theme/scope.js +80 -0
- package/dist/theme/scope.js.map +1 -0
- package/dist/theme/styles.js +39 -0
- package/dist/theme/styles.js.map +1 -0
- package/dist/theme-scope.d.ts +56 -0
- package/dist/theme-scope.js +127 -0
- package/dist/theme-scope.js.map +1 -0
- package/dist/tokens/defaults.d.ts +407 -0
- package/dist/tokens/defaults.js +403 -0
- package/dist/tokens/defaults.js.map +1 -0
- package/dist/typography/fonts.js +84 -0
- package/dist/typography/fonts.js.map +1 -0
- package/dist/typography/roles.d.ts +10 -0
- package/dist/typography/roles.js +82 -0
- package/dist/typography/roles.js.map +1 -0
- package/package.json +132 -4
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { IconStyleContext } from "../glyphs/icon-style.js";
|
|
2
|
+
import { CheckGlyph } from "../glyphs/index.js";
|
|
3
|
+
import { useTheme } from "../theme/scope.js";
|
|
4
|
+
import { composeStyles } from "../theme/styles.js";
|
|
5
|
+
import { useTypeRole } from "../typography/roles.js";
|
|
6
|
+
import { withOpacity } from "../theme/color.js";
|
|
7
|
+
import { styles, stylesOf } from "./styles.js";
|
|
8
|
+
import { c } from "react/compiler-runtime";
|
|
9
|
+
import { View } from "react-native";
|
|
10
|
+
import { jsx } from "react/jsx-runtime";
|
|
11
|
+
import Animated, { Easing, useAnimatedStyle, useReducedMotion, withTiming } from "react-native-reanimated";
|
|
12
|
+
//#region src/chip/index.tsx
|
|
13
|
+
const CHECK = /* @__PURE__ */ jsx(CheckGlyph, {});
|
|
14
|
+
/**
|
|
15
|
+
* What a chip draws before its label: the check while it is selected, its own
|
|
16
|
+
* icon while it is not, and nothing for an unselected chip with no icon. The
|
|
17
|
+
* slot hands the glyph its colour and size through `useIconStyle()`.
|
|
18
|
+
*/
|
|
19
|
+
function ChipGlyph(t0) {
|
|
20
|
+
const $ = c(10);
|
|
21
|
+
const { color, icon, selected } = t0;
|
|
22
|
+
const own = stylesOf(useTheme());
|
|
23
|
+
const glyph = selected ? CHECK : icon;
|
|
24
|
+
if (glyph === void 0 || glyph === null) return null;
|
|
25
|
+
const T0 = IconStyleContext;
|
|
26
|
+
let t1;
|
|
27
|
+
if ($[0] !== color) {
|
|
28
|
+
t1 = iconStyleOf(color);
|
|
29
|
+
$[0] = color;
|
|
30
|
+
$[1] = t1;
|
|
31
|
+
} else t1 = $[1];
|
|
32
|
+
const T1 = View;
|
|
33
|
+
const t2 = composeStyles(styles.glyph, own.glyphStart);
|
|
34
|
+
let t3;
|
|
35
|
+
if ($[2] !== T1 || $[3] !== glyph || $[4] !== t2) {
|
|
36
|
+
t3 = /* @__PURE__ */ jsx(T1, {
|
|
37
|
+
style: t2,
|
|
38
|
+
children: glyph
|
|
39
|
+
});
|
|
40
|
+
$[2] = T1;
|
|
41
|
+
$[3] = glyph;
|
|
42
|
+
$[4] = t2;
|
|
43
|
+
$[5] = t3;
|
|
44
|
+
} else t3 = $[5];
|
|
45
|
+
let t4;
|
|
46
|
+
if ($[6] !== T0 || $[7] !== t1 || $[8] !== t3) {
|
|
47
|
+
t4 = /* @__PURE__ */ jsx(T0, {
|
|
48
|
+
value: t1,
|
|
49
|
+
children: t3
|
|
50
|
+
});
|
|
51
|
+
$[6] = T0;
|
|
52
|
+
$[7] = t1;
|
|
53
|
+
$[8] = t3;
|
|
54
|
+
$[9] = t4;
|
|
55
|
+
} else t4 = $[9];
|
|
56
|
+
return t4;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The label a chip draws, on one line and cut short with an ellipsis, in the
|
|
60
|
+
* colour `useEasedColors` eases.
|
|
61
|
+
*/
|
|
62
|
+
function ChipLabel(t0) {
|
|
63
|
+
const $ = c(6);
|
|
64
|
+
const { children, color } = t0;
|
|
65
|
+
const role = useTypeRole("labelLarge");
|
|
66
|
+
let t1;
|
|
67
|
+
if ($[0] !== color || $[1] !== role) {
|
|
68
|
+
t1 = composeStyles(role, styles.label, color);
|
|
69
|
+
$[0] = color;
|
|
70
|
+
$[1] = role;
|
|
71
|
+
$[2] = t1;
|
|
72
|
+
} else t1 = $[2];
|
|
73
|
+
let t2;
|
|
74
|
+
if ($[3] !== children || $[4] !== t1) {
|
|
75
|
+
t2 = /* @__PURE__ */ jsx(Animated.Text, {
|
|
76
|
+
numberOfLines: 1,
|
|
77
|
+
style: t1,
|
|
78
|
+
children
|
|
79
|
+
});
|
|
80
|
+
$[3] = children;
|
|
81
|
+
$[4] = t1;
|
|
82
|
+
$[5] = t2;
|
|
83
|
+
} else t2 = $[5];
|
|
84
|
+
return t2;
|
|
85
|
+
}
|
|
86
|
+
function iconStyleOf(color) {
|
|
87
|
+
return {
|
|
88
|
+
color,
|
|
89
|
+
size: 18
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Records a chip's width for its target, then calls the call site's own
|
|
94
|
+
* `onLayout`. Built by a call rather than declared in a component, which is
|
|
95
|
+
* what react-perf's jsx-no-new-function-as-prop is after; the React Compiler
|
|
96
|
+
* memoises the result on its inputs.
|
|
97
|
+
*/
|
|
98
|
+
function measureThen(setWidth, onLayout) {
|
|
99
|
+
return (event) => {
|
|
100
|
+
setWidth(event.nativeEvent.layout.width);
|
|
101
|
+
onLayout?.(event);
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The colours a chip draws, as the header sets them out. Transparent is
|
|
106
|
+
* written as the colour it eases to or from at no opacity, since Reanimated
|
|
107
|
+
* reads `transparent` as black at none and an ease from it would darken on
|
|
108
|
+
* the way: the fill as the secondary container a selected chip takes, and the
|
|
109
|
+
* rule as the outline it gives up.
|
|
110
|
+
*/
|
|
111
|
+
function paintOf({ colors, stateLayerOpacity }, { assist, disabled, elevated, selected }) {
|
|
112
|
+
const clearFill = withOpacity(colors.secondaryContainer, 0);
|
|
113
|
+
const clearRule = withOpacity(colors.outlineVariant, 0);
|
|
114
|
+
const contained = selected || elevated;
|
|
115
|
+
if (disabled) {
|
|
116
|
+
const content = withOpacity(colors.onSurface, stateLayerOpacity.disabledContent);
|
|
117
|
+
const container = withOpacity(colors.onSurface, stateLayerOpacity.disabledContainer);
|
|
118
|
+
return {
|
|
119
|
+
content,
|
|
120
|
+
fill: contained ? container : clearFill,
|
|
121
|
+
glyph: content,
|
|
122
|
+
layer: colors.onSurface,
|
|
123
|
+
rule: contained ? clearRule : container
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (selected) return {
|
|
127
|
+
content: colors.onSecondaryContainer,
|
|
128
|
+
fill: colors.secondaryContainer,
|
|
129
|
+
glyph: colors.onSecondaryContainer,
|
|
130
|
+
layer: colors.onSecondaryContainer,
|
|
131
|
+
rule: clearRule
|
|
132
|
+
};
|
|
133
|
+
return {
|
|
134
|
+
content: assist ? colors.onSurface : colors.onSurfaceVariant,
|
|
135
|
+
fill: elevated ? colors.surfaceContainerLow : clearFill,
|
|
136
|
+
glyph: colors.primary,
|
|
137
|
+
layer: colors.onSurface,
|
|
138
|
+
rule: elevated ? clearRule : colors.outlineVariant
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The target the header sets out: half the gap chips wrap apart above and
|
|
143
|
+
* below, and across, whatever brings the chip up to 48dp wide.
|
|
144
|
+
*/
|
|
145
|
+
function targetOf(width, { spacing }) {
|
|
146
|
+
const across = Math.max(0, (48 - width) / 2);
|
|
147
|
+
const reach = spacing.sm / 2;
|
|
148
|
+
return {
|
|
149
|
+
bottom: reach,
|
|
150
|
+
left: across,
|
|
151
|
+
right: across,
|
|
152
|
+
top: reach
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* The container's fill and rule and the label's colour, easing to the paint
|
|
157
|
+
* they are given, or there at once under reduced motion.
|
|
158
|
+
*/
|
|
159
|
+
function useEasedColors(t0) {
|
|
160
|
+
const $ = c(3);
|
|
161
|
+
const { content, fill, rule } = t0;
|
|
162
|
+
const { motion } = useTheme();
|
|
163
|
+
const reduceMotion = useReducedMotion();
|
|
164
|
+
const timing = {
|
|
165
|
+
duration: motion.durationShort2,
|
|
166
|
+
easing: Easing.bezier(...motion.easingStandard)
|
|
167
|
+
};
|
|
168
|
+
const container = useAnimatedStyle(() => {
|
|
169
|
+
"worklet";
|
|
170
|
+
return {
|
|
171
|
+
backgroundColor: reduceMotion ? fill : withTiming(fill, timing),
|
|
172
|
+
borderColor: reduceMotion ? rule : withTiming(rule, timing)
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
const label = useAnimatedStyle(() => {
|
|
176
|
+
"worklet";
|
|
177
|
+
return { color: reduceMotion ? content : withTiming(content, timing) };
|
|
178
|
+
});
|
|
179
|
+
let t1;
|
|
180
|
+
if ($[0] !== container || $[1] !== label) {
|
|
181
|
+
t1 = {
|
|
182
|
+
container,
|
|
183
|
+
label
|
|
184
|
+
};
|
|
185
|
+
$[0] = container;
|
|
186
|
+
$[1] = label;
|
|
187
|
+
$[2] = t1;
|
|
188
|
+
} else t1 = $[2];
|
|
189
|
+
return t1;
|
|
190
|
+
}
|
|
191
|
+
//#endregion
|
|
192
|
+
export { ChipGlyph, ChipLabel, measureThen, paintOf, targetOf, useEasedColors };
|
|
193
|
+
|
|
194
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["ReactNode","Insets","LayoutChangeEvent","TextStyle","ViewStyle","AnimatedStyle","View","Animated","Easing","useAnimatedStyle","useReducedMotion","withTiming","IconStyle","ResolvedTheme","CheckGlyph","IconStyleContext","TARGET_SIZE","withOpacity","useTheme","composeStyles","useTypeRole","GLYPH_SIZE","styles","stylesOf","Paint","content","fill","glyph","layer","rule","CHECK","ChipGlyph","t0","$","_c","color","icon","selected","own","undefined","T0","t1","iconStyleOf","T1","t2","glyphStart","t3","t4","ChipLabel","children","role","label","size","measureThen","setWidth","width","onLayout","event","nativeEvent","layout","paintOf","colors","stateLayerOpacity","assist","disabled","elevated","clearFill","secondaryContainer","clearRule","outlineVariant","contained","onSurface","disabledContent","container","disabledContainer","onSecondaryContainer","onSurfaceVariant","surfaceContainerLow","primary","targetOf","spacing","across","Math","max","reach","sm","bottom","left","right","top","useEasedColors","motion","reduceMotion","timing","duration","durationShort2","easing","bezier","easingStandard","backgroundColor","borderColor","_c"],"sources":["../../src/chip/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport type {\n Insets,\n LayoutChangeEvent,\n TextStyle,\n ViewStyle,\n} from 'react-native'\nimport type { AnimatedStyle } from 'react-native-reanimated'\n\nimport { View } from 'react-native'\nimport Animated, {\n Easing,\n useAnimatedStyle,\n useReducedMotion,\n withTiming,\n} from 'react-native-reanimated'\n\nimport type { IconStyle } from '../glyphs/icon-style'\nimport type { ResolvedTheme } from '../theme/scope'\n\nimport { CheckGlyph } from '../glyphs'\nimport { IconStyleContext } from '../glyphs/icon-style'\nimport { TARGET_SIZE } from '../press'\nimport { withOpacity } from '../theme/color'\nimport { useTheme } from '../theme/scope'\nimport { composeStyles } from '../theme/styles'\nimport { useTypeRole } from '../typography/roles'\nimport { GLYPH_SIZE, styles, stylesOf } from './styles'\n\n// The pill the chips page draws, shared by Chip and ChipGroup's chip so the\n// two cannot drift, as web's `src/chip` is. Not a component of the library's\n// own and not exported from the package. A 32dp pill with an 8dp corner, 16dp\n// of inline padding and a 1dp rule, its label in label-large.\n//\n// An unselected chip is an outline-variant rule around nothing. **An elevated\n// chip trades the outline for a container**, surface container low at the\n// page's elevation 1, raised to 2 under a pointer; a selected one keeps the\n// secondary container and takes the shadow with it. Its rule stays,\n// transparent, so a chip is one size whichever container it is on.\n//\n// The check takes the icon's place rather than joining it, so a chip with an\n// icon keeps its width when it is chosen, where one without grows by the\n// slot. The check is what makes the selection legible without colour. An icon\n// is in the primary role, and in the label's colour while disabled; the check\n// is always in the label's. The slot is the page's 18dp, and a chip drawing\n// one pads 8dp on that side rather than 16.\n//\n// **The label is one line, cut short with an ellipsis.** The chip is never\n// wider than what holds it, which leaves the label a width to be cut at, and a\n// screen reader still reads all of it. The height is a floor rather than a\n// fixed size, so a label the device's text size enlarges grows the chip\n// rather than running out of it.\n//\n// The fill, the rule and the label's colour ease over `durationShort2` on the\n// standard curve, and change at once under reduced motion. The check appears\n// at once, as on web, and the shadow moves at once, as a button's does.\n//\n// **Disabled is the page's colour at an opacity, translucent**, as a button's\n// is: the label on-surface at `disabledContent`, a selected or elevated chip's\n// container on-surface at `disabledContainer`, and an unselected one's rule at\n// the same. A disabled chip casts no shadow.\n//\n// The state layers, the ripple and the focus ring are src/press's: on-surface\n// over an unselected or elevated chip, on-secondary-container over a selected\n// one.\n//\n// **The target departs from the page's 48dp, as web's does.** Across, it is\n// the chip's width or 48dp, whichever is wider, centred on the chip. Up and\n// down it reaches half the `spacing.sm` that chips wrap apart, not the 8dp a\n// 48dp target would ask: a full reach would lay one row's target over the next\n// one's, and a press just under one chip could go to the chip below it.\n// Halfway, two rows' targets meet in the middle of the gap.\n\n/** The colours a chip draws in one state. */\ntype Paint = {\n /** The label's colour. */\n readonly content: string\n readonly fill: string\n /**\n * The glyph's colour: the label's for the check, and for an icon the\n * primary role's, or the label's while the chip is disabled.\n */\n readonly glyph: string\n /** The state layer's and the ripple's colour. */\n readonly layer: string\n readonly rule: string\n}\n\nconst CHECK = <CheckGlyph />\n\n/**\n * What a chip draws before its label: the check while it is selected, its own\n * icon while it is not, and nothing for an unselected chip with no icon. The\n * slot hands the glyph its colour and size through `useIconStyle()`.\n */\nfunction ChipGlyph({\n color,\n icon,\n selected,\n}: {\n readonly color: string\n readonly icon: ReactNode\n readonly selected: boolean\n}) {\n const own = stylesOf(useTheme())\n const glyph = selected ? CHECK : icon\n\n if (glyph === undefined || glyph === null) {\n return null\n }\n\n return (\n <IconStyleContext value={iconStyleOf(color)}>\n <View style={composeStyles<ViewStyle>(styles.glyph, own.glyphStart)}>\n {glyph}\n </View>\n </IconStyleContext>\n )\n}\n\n/**\n * The label a chip draws, on one line and cut short with an ellipsis, in the\n * colour `useEasedColors` eases.\n */\nfunction ChipLabel({\n children,\n color,\n}: {\n readonly children: ReactNode\n readonly color: AnimatedStyle<TextStyle>\n}) {\n const role = useTypeRole('labelLarge')\n\n return (\n <Animated.Text\n numberOfLines={1}\n style={composeStyles<AnimatedStyle<TextStyle>>(role, styles.label, color)}\n >\n {children}\n </Animated.Text>\n )\n}\n\nfunction iconStyleOf(color: string): IconStyle {\n return { color, size: GLYPH_SIZE }\n}\n\n/**\n * Records a chip's width for its target, then calls the call site's own\n * `onLayout`. Built by a call rather than declared in a component, which is\n * what react-perf's jsx-no-new-function-as-prop is after; the React Compiler\n * memoises the result on its inputs.\n */\nfunction measureThen(\n setWidth: (width: number) => void,\n onLayout: ((event: LayoutChangeEvent) => void) | null | undefined,\n) {\n return (event: LayoutChangeEvent) => {\n setWidth(event.nativeEvent.layout.width)\n onLayout?.(event)\n }\n}\n\n/**\n * The colours a chip draws, as the header sets them out. Transparent is\n * written as the colour it eases to or from at no opacity, since Reanimated\n * reads `transparent` as black at none and an ease from it would darken on\n * the way: the fill as the secondary container a selected chip takes, and the\n * rule as the outline it gives up.\n */\nfunction paintOf(\n { colors, stateLayerOpacity }: ResolvedTheme,\n {\n assist,\n disabled,\n elevated,\n selected,\n }: {\n readonly assist: boolean\n readonly disabled: boolean\n readonly elevated: boolean\n readonly selected: boolean\n },\n): Paint {\n const clearFill = withOpacity(colors.secondaryContainer, 0)\n const clearRule = withOpacity(colors.outlineVariant, 0)\n const contained = selected || elevated\n\n if (disabled) {\n const content = withOpacity(\n colors.onSurface,\n stateLayerOpacity.disabledContent,\n )\n const container = withOpacity(\n colors.onSurface,\n stateLayerOpacity.disabledContainer,\n )\n\n return {\n content,\n fill: contained ? container : clearFill,\n glyph: content,\n layer: colors.onSurface,\n rule: contained ? clearRule : container,\n }\n }\n\n if (selected) {\n return {\n content: colors.onSecondaryContainer,\n fill: colors.secondaryContainer,\n glyph: colors.onSecondaryContainer,\n layer: colors.onSecondaryContainer,\n rule: clearRule,\n }\n }\n\n return {\n content: assist ? colors.onSurface : colors.onSurfaceVariant,\n fill: elevated ? colors.surfaceContainerLow : clearFill,\n glyph: colors.primary,\n layer: colors.onSurface,\n rule: elevated ? clearRule : colors.outlineVariant,\n }\n}\n\n/**\n * The target the header sets out: half the gap chips wrap apart above and\n * below, and across, whatever brings the chip up to 48dp wide.\n */\nfunction targetOf(width: number, { spacing }: ResolvedTheme): Insets {\n const across = Math.max(0, (TARGET_SIZE - width) / 2)\n const reach = spacing.sm / 2\n\n return { bottom: reach, left: across, right: across, top: reach }\n}\n\n/**\n * The container's fill and rule and the label's colour, easing to the paint\n * they are given, or there at once under reduced motion.\n */\nfunction useEasedColors({ content, fill, rule }: Paint) {\n const { motion } = useTheme()\n const reduceMotion = useReducedMotion()\n const timing = {\n duration: motion.durationShort2,\n easing: Easing.bezier(...motion.easingStandard),\n }\n\n const container = useAnimatedStyle(() => {\n 'worklet'\n return {\n backgroundColor: reduceMotion ? fill : withTiming(fill, timing),\n borderColor: reduceMotion ? rule : withTiming(rule, timing),\n }\n })\n const label = useAnimatedStyle(() => {\n 'worklet'\n return { color: reduceMotion ? content : withTiming(content, timing) }\n })\n\n return { container, label }\n}\n\nexport { ChipGlyph, ChipLabel, measureThen, paintOf, targetOf, useEasedColors }\nexport type { Paint }\n"],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { themedStyles } from "../theme/styles.js";
|
|
2
|
+
import { StyleSheet } from "react-native";
|
|
3
|
+
const styles = StyleSheet.create({
|
|
4
|
+
glyph: {
|
|
5
|
+
alignItems: "center",
|
|
6
|
+
flexShrink: 0,
|
|
7
|
+
height: 18,
|
|
8
|
+
justifyContent: "center",
|
|
9
|
+
width: 18
|
|
10
|
+
},
|
|
11
|
+
label: {
|
|
12
|
+
flexShrink: 1,
|
|
13
|
+
minWidth: 0
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
const stylesOf = themedStyles(({ radii, sizing, spacing }) => StyleSheet.create({
|
|
17
|
+
glyphStart: { marginStart: -spacing.sm },
|
|
18
|
+
pill: {
|
|
19
|
+
alignItems: "center",
|
|
20
|
+
borderRadius: radii.sm,
|
|
21
|
+
borderWidth: 1,
|
|
22
|
+
flexDirection: "row",
|
|
23
|
+
gap: spacing.sm,
|
|
24
|
+
maxWidth: "100%",
|
|
25
|
+
minHeight: sizing.controlXs,
|
|
26
|
+
paddingHorizontal: spacing.lg
|
|
27
|
+
}
|
|
28
|
+
}));
|
|
29
|
+
const shadowsOf = themedStyles(({ shadows }) => StyleSheet.create({
|
|
30
|
+
elevation1: { boxShadow: shadows.elevation1 },
|
|
31
|
+
elevation2: { boxShadow: shadows.elevation2 }
|
|
32
|
+
}));
|
|
33
|
+
//#endregion
|
|
34
|
+
export { shadowsOf, styles, stylesOf };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.js","names":["StyleSheet","themedStyles","GLYPH_SIZE","RULE_WIDTH","styles","create","glyph","alignItems","flexShrink","height","justifyContent","width","label","minWidth","stylesOf","radii","sizing","spacing","glyphStart","marginStart","sm","pill","borderRadius","borderWidth","flexDirection","gap","maxWidth","minHeight","controlXs","paddingHorizontal","lg","shadowsOf","shadows","elevation1","boxShadow","elevation2"],"sources":["../../src/chip/styles.ts"],"sourcesContent":["import { StyleSheet } from 'react-native'\n\nimport { themedStyles } from '../theme/styles'\n\n// The pill the chips page draws, shared by the two components that draw one:\n// Chip, and ChipGroup's chip. See the header of `./index.tsx`.\n\n// The page's icon size for a chip. A literal, as on web: the theme has no\n// scale for icon sizes.\nconst GLYPH_SIZE = 18\n\n// The rule every chip draws, transparent on a container of its own, so a chip\n// is one size whichever container it is on.\nconst RULE_WIDTH = 1\n\nconst styles = StyleSheet.create({\n glyph: {\n alignItems: 'center',\n flexShrink: 0,\n height: GLYPH_SIZE,\n justifyContent: 'center',\n width: GLYPH_SIZE,\n },\n // The label gives way before anything else in the pill does, and `minWidth`\n // lets it narrow below its text, which React Native Web otherwise holds it\n // at, so the ellipsis has somewhere to fall.\n label: {\n flexShrink: 1,\n minWidth: 0,\n },\n})\n\nconst stylesOf = themedStyles(({ radii, sizing, spacing }) =>\n StyleSheet.create({\n // The pill's inline padding is 8dp on the side the glyph is on, so the\n // slot gives back the difference rather than the pill padding each side\n // apart, as web's does.\n glyphStart: {\n marginStart: -spacing.sm,\n },\n // No block padding, as on web: the label's own line box is what keeps an\n // enlarged label off the pill's edge, and a padding off the spacing scale\n // would grow the pill past 32dp under a scheme with a roomier one.\n pill: {\n alignItems: 'center',\n borderRadius: radii.sm,\n borderWidth: RULE_WIDTH,\n flexDirection: 'row',\n gap: spacing.sm,\n maxWidth: '100%',\n minHeight: sizing.controlXs,\n paddingHorizontal: spacing.lg,\n },\n }),\n)\n\nconst shadowsOf = themedStyles(({ shadows }) =>\n StyleSheet.create({\n elevation1: { boxShadow: shadows.elevation1 },\n elevation2: { boxShadow: shadows.elevation2 },\n }),\n)\n\nexport { GLYPH_SIZE, RULE_WIDTH, shadowsOf, styles, stylesOf }\n"],"mappings":";;AAeA,MAAMI,SAASJ,WAAWK,OAAO;CAC/BC,OAAO;EACLC,YAAY;EACZC,YAAY;EACZC,QAAAA;EACAC,gBAAgB;EAChBC,OAAAA;CACF;CAIAC,OAAO;EACLJ,YAAY;EACZK,UAAU;CACZ;AACF,CAAC;AAED,MAAMC,WAAWb,cAAc,EAAEc,OAAOC,QAAQC,cAC9CjB,WAAWK,OAAO;CAIhBa,YAAY,EACVC,aAAa,CAACF,QAAQG,GACxB;CAIAC,MAAM;EACJd,YAAY;EACZe,cAAcP,MAAMK;EACpBG,aAAAA;EACAC,eAAe;EACfC,KAAKR,QAAQG;EACbM,UAAU;EACVC,WAAWX,OAAOY;EAClBC,mBAAmBZ,QAAQa;CAC7B;AACF,CAAC,CACH;AAEA,MAAMC,YAAY9B,cAAc,EAAE+B,cAChChC,WAAWK,OAAO;CAChB4B,YAAY,EAAEC,WAAWF,QAAQC,WAAW;CAC5CE,YAAY,EAAED,WAAWF,QAAQG,WAAW;AAC9C,CAAC,CACH"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
//#region src/clipboard/index.ts
|
|
3
|
+
let clipboard;
|
|
4
|
+
let loading;
|
|
5
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
6
|
+
async function load() {
|
|
7
|
+
try {
|
|
8
|
+
return await import(
|
|
9
|
+
/* @vite-ignore */
|
|
10
|
+
"expo-clipboard"
|
|
11
|
+
);
|
|
12
|
+
} catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async function settle() {
|
|
17
|
+
loading ??= load().then((settled) => {
|
|
18
|
+
clipboard = settled;
|
|
19
|
+
for (const listener of listeners) listener();
|
|
20
|
+
return settled;
|
|
21
|
+
});
|
|
22
|
+
return loading;
|
|
23
|
+
}
|
|
24
|
+
function snapshot() {
|
|
25
|
+
settle();
|
|
26
|
+
return clipboard;
|
|
27
|
+
}
|
|
28
|
+
function subscribe(listener) {
|
|
29
|
+
settle();
|
|
30
|
+
listeners.add(listener);
|
|
31
|
+
return () => {
|
|
32
|
+
listeners.delete(listener);
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Whether expo-clipboard is there to write to: `false` once importing it has
|
|
37
|
+
* failed, and `true` until then, so a control that copies draws at once in
|
|
38
|
+
* the app that installed it rather than a moment after.
|
|
39
|
+
*/
|
|
40
|
+
function useClipboardAvailable() {
|
|
41
|
+
return useSyncExternalStore(subscribe, snapshot) !== null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Puts text on the clipboard, and rejects when it did not get there: when
|
|
45
|
+
* expo-clipboard is not installed, or when its write says it failed. On iOS
|
|
46
|
+
* and Android the write always lands. Under React Native Web it fails only
|
|
47
|
+
* where the browser refuses its clipboard and its older copy command throws
|
|
48
|
+
* as well, since expo-clipboard falls back to the second itself.
|
|
49
|
+
*/
|
|
50
|
+
async function writeClipboard(text) {
|
|
51
|
+
const settled = await settle();
|
|
52
|
+
if (settled === null) throw new Error("expo-clipboard is not installed");
|
|
53
|
+
if (!await settled.setStringAsync(text)) throw new Error("The clipboard refused the write");
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { useClipboardAvailable, writeClipboard };
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["useSyncExternalStore","Clipboard","setStringAsync","text","Promise","clipboard","loading","listeners","Set","load","settle","then","settled","listener","snapshot","subscribe","add","delete","useClipboardAvailable","writeClipboard","Error"],"sources":["../../src/clipboard/index.ts"],"sourcesContent":["import { useSyncExternalStore } from 'react'\n\ntype Clipboard = {\n readonly setStringAsync: (text: string) => Promise<boolean>\n}\n\n// expo-clipboard is an optional peer, so it is imported where its absence can\n// be caught, as src/typography/fonts.ts imports expo-font: Metro takes an\n// import inside a `try` as optional and bundles an app without it. Until the\n// import settles the module is `undefined`, and `null` once it has failed,\n// which is also what an app that installed it without rebuilding gets, since\n// the package throws on import when its native half is missing.\nlet clipboard: Clipboard | null | undefined\nlet loading: Promise<Clipboard | null> | undefined\nconst listeners = new Set<() => void>()\n\nasync function load(): Promise<Clipboard | null> {\n try {\n return await import(/* @vite-ignore */ 'expo-clipboard')\n } catch {\n return null\n }\n}\n\nasync function settle() {\n loading ??= load().then((settled) => {\n clipboard = settled\n\n for (const listener of listeners) {\n listener()\n }\n\n return settled\n })\n\n return loading\n}\n\nfunction snapshot() {\n void settle()\n return clipboard\n}\n\nfunction subscribe(listener: () => void) {\n void settle()\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n}\n\n/**\n * Whether expo-clipboard is there to write to: `false` once importing it has\n * failed, and `true` until then, so a control that copies draws at once in\n * the app that installed it rather than a moment after.\n */\nfunction useClipboardAvailable(): boolean {\n return useSyncExternalStore(subscribe, snapshot) !== null\n}\n\n/**\n * Puts text on the clipboard, and rejects when it did not get there: when\n * expo-clipboard is not installed, or when its write says it failed. On iOS\n * and Android the write always lands. Under React Native Web it fails only\n * where the browser refuses its clipboard and its older copy command throws\n * as well, since expo-clipboard falls back to the second itself.\n */\nasync function writeClipboard(text: string): Promise<void> {\n const settled = await settle()\n\n if (settled === null) {\n throw new Error('expo-clipboard is not installed')\n }\n\n if (!(await settled.setStringAsync(text))) {\n throw new Error('The clipboard refused the write')\n }\n}\n\nexport { useClipboardAvailable, writeClipboard }\n"],"mappings":";;AAYA,IAAIK;AACJ,IAAIC;AACJ,MAAMC,4BAAY,IAAIC,IAAgB;AAEtC,eAAeC,OAAkC;CAC/C,IAAI;EACF,OAAO,MAAM;;GAA0B;;CACzC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,eAAeC,SAAS;CACtBJ,YAAYG,KAAK,CAAC,CAACE,MAAMC,YAAY;EACnCP,YAAYO;EAEZ,KAAK,MAAMC,YAAYN,WACrBM,SAAS;EAGX,OAAOD;CACT,CAAC;CAED,OAAON;AACT;AAEA,SAASQ,WAAW;CAClB,OAAY;CACZ,OAAOT;AACT;AAEA,SAASU,UAAUF,UAAsB;CACvC,OAAY;CACZN,UAAUS,IAAIH,QAAQ;CACtB,aAAa;EACXN,UAAUU,OAAOJ,QAAQ;CAC3B;AACF;;;;;;AAOA,SAAAK,wBAAA;CAAA,OACSlB,qBAAqBe,WAAWD,QAAQ,MAAM;AAAI;;;;;;;;AAU3D,eAAeK,eAAehB,MAA6B;CACzD,MAAMS,UAAU,MAAMF,OAAO;CAE7B,IAAIE,YAAY,MACd,MAAM,IAAIQ,MAAM,iCAAiC;CAGnD,IAAI,CAAE,MAAMR,QAAQV,eAAeC,IAAI,GACrC,MAAM,IAAIiB,MAAM,iCAAiC;AAErD"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { MarkImageProps } from "../../mark/index.js";
|
|
2
|
+
import { StyleProp, View, ViewProps, ViewStyle } from "react-native";
|
|
3
|
+
import { Ref } from "react";
|
|
4
|
+
//#region src/components/avatar/index.d.ts
|
|
5
|
+
type AvatarProps = Omit<ViewProps, 'children' | 'style'> & {
|
|
6
|
+
/**
|
|
7
|
+
* Hides the avatar from screen readers, for one beside the person's name,
|
|
8
|
+
* such as a row whose headline is the name or a byline, where it would
|
|
9
|
+
* otherwise announce the name a second time. `name` still supplies the
|
|
10
|
+
* initials, and is not announced.
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
readonly decorative?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Props for the photo's own `Image`: `crossOrigin` and `referrerPolicy`
|
|
16
|
+
* for where it is served from, and `resizeMethod`, `fadeDuration` and
|
|
17
|
+
* `progressiveRenderingEnabled` for how Android decodes and shows it.
|
|
18
|
+
*/
|
|
19
|
+
readonly imgProps?: MarkImageProps;
|
|
20
|
+
/**
|
|
21
|
+
* The person this represents. Supplies both the initials and the
|
|
22
|
+
* accessible name, so a screen reader announces who it is rather than
|
|
23
|
+
* reading two letters aloud.
|
|
24
|
+
*
|
|
25
|
+
* A display name, as a reader would see it written: the initials are its
|
|
26
|
+
* first and last words. A title before the name ("Dr."), a generational
|
|
27
|
+
* suffix after it ("Jr.", "III") and an aside in brackets at its end
|
|
28
|
+
* ("(she/her)") are passed over, as is punctuation a word opens with. A
|
|
29
|
+
* name written without spaces between its words, as Japanese and Chinese
|
|
30
|
+
* names are, is one word, and takes one initial.
|
|
31
|
+
*/
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly ref?: Ref<View>;
|
|
34
|
+
/**
|
|
35
|
+
* Whether an avatar with no initials to take, for a blank `name`, draws
|
|
36
|
+
* Material Design's anonymous person. `false` leaves the tinted disc
|
|
37
|
+
* empty, for a loading skeleton.
|
|
38
|
+
* @default true
|
|
39
|
+
*/
|
|
40
|
+
readonly showPersonIcon?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Diameter: `sm` 36dp, `md` 40dp, `lg` 56dp.
|
|
43
|
+
* @default 'md'
|
|
44
|
+
*/
|
|
45
|
+
readonly size?: 'lg' | 'md' | 'sm';
|
|
46
|
+
/**
|
|
47
|
+
* A photo to show in place of the initials. The initials stay until it has
|
|
48
|
+
* loaded, and come back if it fails.
|
|
49
|
+
*/
|
|
50
|
+
readonly src?: string;
|
|
51
|
+
readonly style?: StyleProp<ViewStyle>;
|
|
52
|
+
/**
|
|
53
|
+
* Which container and on-container colour pair to tint with.
|
|
54
|
+
* @default 'primary'
|
|
55
|
+
*/
|
|
56
|
+
readonly tone?: 'negative' | 'positive' | 'primary' | 'secondary' | 'tertiary';
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* A person, as a disc holding their photo or, until it loads or when there
|
|
60
|
+
* is none, their initials. `name` is both where the initials come from and
|
|
61
|
+
* what a screen reader announces, so it is required even with a photo.
|
|
62
|
+
*
|
|
63
|
+
* ```tsx
|
|
64
|
+
* <Avatar name="Ada Lovelace" size="lg" src={photo} />
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* It is announced as an image named by `name`. When the person's name is
|
|
68
|
+
* already written next to the avatar, mark it `decorative`, so a screen
|
|
69
|
+
* reader reads the name once. A blank name names nothing, so the avatar is
|
|
70
|
+
* then a plain view, which a screen reader passes over rather than reading
|
|
71
|
+
* as an image with no name.
|
|
72
|
+
*
|
|
73
|
+
* Reach for ProductIcon when what is drawn is not a person; the two share
|
|
74
|
+
* their sizes, so either fills the same slot in a row or a card.
|
|
75
|
+
*
|
|
76
|
+
* The initials are taken in the device's locale. `style`, `ref` and `testID`
|
|
77
|
+
* land on the disc.
|
|
78
|
+
*/
|
|
79
|
+
declare function Avatar({ size, tone, ...props }: AvatarProps): import("react").JSX.Element;
|
|
80
|
+
//#endregion
|
|
81
|
+
export { Avatar, type AvatarProps };
|
|
82
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Mark } from "../../mark/index.js";
|
|
2
|
+
import { c } from "react/compiler-runtime";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/avatar/index.tsx
|
|
5
|
+
/**
|
|
6
|
+
* A person, as a disc holding their photo or, until it loads or when there
|
|
7
|
+
* is none, their initials. `name` is both where the initials come from and
|
|
8
|
+
* what a screen reader announces, so it is required even with a photo.
|
|
9
|
+
*
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <Avatar name="Ada Lovelace" size="lg" src={photo} />
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* It is announced as an image named by `name`. When the person's name is
|
|
15
|
+
* already written next to the avatar, mark it `decorative`, so a screen
|
|
16
|
+
* reader reads the name once. A blank name names nothing, so the avatar is
|
|
17
|
+
* then a plain view, which a screen reader passes over rather than reading
|
|
18
|
+
* as an image with no name.
|
|
19
|
+
*
|
|
20
|
+
* Reach for ProductIcon when what is drawn is not a person; the two share
|
|
21
|
+
* their sizes, so either fills the same slot in a row or a card.
|
|
22
|
+
*
|
|
23
|
+
* The initials are taken in the device's locale. `style`, `ref` and `testID`
|
|
24
|
+
* land on the disc.
|
|
25
|
+
*/
|
|
26
|
+
function Avatar(t0) {
|
|
27
|
+
const $ = c(8);
|
|
28
|
+
let props;
|
|
29
|
+
let t1;
|
|
30
|
+
let t2;
|
|
31
|
+
if ($[0] !== t0) {
|
|
32
|
+
({size: t1, tone: t2, ...props} = t0);
|
|
33
|
+
$[0] = t0;
|
|
34
|
+
$[1] = props;
|
|
35
|
+
$[2] = t1;
|
|
36
|
+
$[3] = t2;
|
|
37
|
+
} else {
|
|
38
|
+
props = $[1];
|
|
39
|
+
t1 = $[2];
|
|
40
|
+
t2 = $[3];
|
|
41
|
+
}
|
|
42
|
+
const size = t1 === void 0 ? "md" : t1;
|
|
43
|
+
const tone = t2 === void 0 ? "primary" : t2;
|
|
44
|
+
let t3;
|
|
45
|
+
if ($[4] !== props || $[5] !== size || $[6] !== tone) {
|
|
46
|
+
t3 = /* @__PURE__ */ jsx(Mark, {
|
|
47
|
+
...props,
|
|
48
|
+
kind: "person",
|
|
49
|
+
size,
|
|
50
|
+
tone
|
|
51
|
+
});
|
|
52
|
+
$[4] = props;
|
|
53
|
+
$[5] = size;
|
|
54
|
+
$[6] = tone;
|
|
55
|
+
$[7] = t3;
|
|
56
|
+
} else t3 = $[7];
|
|
57
|
+
return t3;
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
export { Avatar };
|
|
61
|
+
|
|
62
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["Ref","StyleProp","View","ViewProps","ViewStyle","MarkImageProps","Mark","AvatarProps","Omit","decorative","imgProps","name","ref","showPersonIcon","size","src","style","tone","Avatar","t0","$","_c","props","t1","t2","undefined","t3","_c"],"sources":["../../../src/components/avatar/index.tsx"],"sourcesContent":["import type { Ref } from 'react'\nimport type { StyleProp, View, ViewProps, ViewStyle } from 'react-native'\n\nimport type { MarkImageProps } from '../../mark'\n\nimport { Mark } from '../../mark'\n\n// A person, drawn as a disc with the photo cropped to fill it, as kanso-ui's\n// Avatar draws one. The box, the sizes, the tones, the photo's loading and\n// the labelling are the mark's in `src/mark`, which ProductIcon draws a thing\n// through as well, so a person and a thing fill the same slot.\n//\n// Which tone a given person gets is the consuming app's decision, since the\n// cycle of colours belongs where the list of people is.\n\ntype AvatarProps = Omit<ViewProps, 'children' | 'style'> & {\n /**\n * Hides the avatar from screen readers, for one beside the person's name,\n * such as a row whose headline is the name or a byline, where it would\n * otherwise announce the name a second time. `name` still supplies the\n * initials, and is not announced.\n * @default false\n */\n readonly decorative?: boolean\n /**\n * Props for the photo's own `Image`: `crossOrigin` and `referrerPolicy`\n * for where it is served from, and `resizeMethod`, `fadeDuration` and\n * `progressiveRenderingEnabled` for how Android decodes and shows it.\n */\n readonly imgProps?: MarkImageProps\n /**\n * The person this represents. Supplies both the initials and the\n * accessible name, so a screen reader announces who it is rather than\n * reading two letters aloud.\n *\n * A display name, as a reader would see it written: the initials are its\n * first and last words. A title before the name (\"Dr.\"), a generational\n * suffix after it (\"Jr.\", \"III\") and an aside in brackets at its end\n * (\"(she/her)\") are passed over, as is punctuation a word opens with. A\n * name written without spaces between its words, as Japanese and Chinese\n * names are, is one word, and takes one initial.\n */\n readonly name: string\n readonly ref?: Ref<View>\n /**\n * Whether an avatar with no initials to take, for a blank `name`, draws\n * Material Design's anonymous person. `false` leaves the tinted disc\n * empty, for a loading skeleton.\n * @default true\n */\n readonly showPersonIcon?: boolean\n /**\n * Diameter: `sm` 36dp, `md` 40dp, `lg` 56dp.\n * @default 'md'\n */\n readonly size?: 'lg' | 'md' | 'sm'\n /**\n * A photo to show in place of the initials. The initials stay until it has\n * loaded, and come back if it fails.\n */\n readonly src?: string\n readonly style?: StyleProp<ViewStyle>\n /**\n * Which container and on-container colour pair to tint with.\n * @default 'primary'\n */\n readonly tone?: 'negative' | 'positive' | 'primary' | 'secondary' | 'tertiary'\n}\n\n/**\n * A person, as a disc holding their photo or, until it loads or when there\n * is none, their initials. `name` is both where the initials come from and\n * what a screen reader announces, so it is required even with a photo.\n *\n * ```tsx\n * <Avatar name=\"Ada Lovelace\" size=\"lg\" src={photo} />\n * ```\n *\n * It is announced as an image named by `name`. When the person's name is\n * already written next to the avatar, mark it `decorative`, so a screen\n * reader reads the name once. A blank name names nothing, so the avatar is\n * then a plain view, which a screen reader passes over rather than reading\n * as an image with no name.\n *\n * Reach for ProductIcon when what is drawn is not a person; the two share\n * their sizes, so either fills the same slot in a row or a card.\n *\n * The initials are taken in the device's locale. `style`, `ref` and `testID`\n * land on the disc.\n */\nfunction Avatar({ size = 'md', tone = 'primary', ...props }: AvatarProps) {\n return <Mark {...props} kind=\"person\" size={size} tone={tone} />\n}\n\nexport type { AvatarProps }\n\nexport { Avatar }\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA0FA,SAAAkB,OAAAC,IAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAAA,IAAAC;CAAA,IAAAC;CAAA,IAAAC;CAAA,IAAAJ,EAAA,OAAAD,IAAA;EAAgB,CAAA,CAAAL,MAAAS,IAAAN,MAAAO,IAAA,GAAAF,SAAAH;EAAwDC,EAAA,KAAAD;EAAAC,EAAA,KAAAE;EAAAF,EAAA,KAAAG;EAAAH,EAAA,KAAAI;CAAA,OAAA;EAAAF,QAAAF,EAAA;EAAAG,KAAAH,EAAA;EAAAI,KAAAJ,EAAA;CAAA;CAAtD,MAAAN,OAAAS,OAAAE,KAAAA,IAAA,OAAAF;CAAa,MAAAN,OAAAO,OAAAC,KAAAA,IAAA,YAAAD;CAAgB,IAAAE;CAAA,IAAAN,EAAA,OAAAE,SAAAF,EAAA,OAAAN,QAAAM,EAAA,OAAAH,MAAA;EACtCS,KAAA,oBAAC,MAAD;GAAK,GAAKJ;GAAY,MAAA;GAAeR;GAAYG;EAAI,CAAA;EAAIG,EAAA,KAAAE;EAAAF,EAAA,KAAAN;EAAAM,EAAA,KAAAH;EAAAG,EAAA,KAAAM;CAAA,OAAAA,KAAAN,EAAA;CAAA,OAAzDM;AAAyD"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ButtonLinkForm, ButtonPressForm, ButtonToggleForm } from "../../button/index.js";
|
|
2
|
+
import { PressableProps, StyleProp, View, ViewStyle } from "react-native";
|
|
3
|
+
import { ReactNode, Ref } from "react";
|
|
4
|
+
//#region src/components/button/index.d.ts
|
|
5
|
+
type ButtonForm = ButtonLinkForm | ButtonPressForm | (ButtonToggleForm & {
|
|
6
|
+
/**
|
|
7
|
+
* A toggle takes any variant but `text`, which the page gives no
|
|
8
|
+
* selected colours.
|
|
9
|
+
*/
|
|
10
|
+
readonly variant?: Exclude<ButtonVariant, 'text'>;
|
|
11
|
+
});
|
|
12
|
+
type ButtonProps = ButtonForm & Omit<PressableProps, 'children' | 'disabled' | 'style'> & {
|
|
13
|
+
/** The label. */
|
|
14
|
+
readonly children?: ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* Draws no press ripple. The state layer is unaffected.
|
|
17
|
+
* @default false
|
|
18
|
+
*/
|
|
19
|
+
readonly disableRipple?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* An icon before the label, at the page's icon size for the button's
|
|
22
|
+
* size: 20dp at `xs` and `md`, 24dp at `lg`, 32dp at `xl` and 40dp at
|
|
23
|
+
* `xxl`. The slot hands it the label's colour and that size through
|
|
24
|
+
* `useIconStyle()`.
|
|
25
|
+
*/
|
|
26
|
+
readonly icon?: ReactNode;
|
|
27
|
+
/**
|
|
28
|
+
* Draws the button disabled, and takes no presses.
|
|
29
|
+
* @default false
|
|
30
|
+
*/
|
|
31
|
+
readonly isDisabled?: boolean;
|
|
32
|
+
readonly ref?: Ref<View>;
|
|
33
|
+
/**
|
|
34
|
+
* The corner the button rests at: `round` is the pill, `square` the
|
|
35
|
+
* page's rounded rectangle, 12dp up to `md`, 16dp at `lg` and 28dp above.
|
|
36
|
+
* Either tightens while pressed, and a toggle trades one for the other
|
|
37
|
+
* once selected.
|
|
38
|
+
* @default 'round'
|
|
39
|
+
*/
|
|
40
|
+
readonly shape?: ButtonShape;
|
|
41
|
+
/**
|
|
42
|
+
* Control height: `xs` 32dp, `md` 40dp, `lg` 56dp, `xl` 96dp, `xxl` 136dp,
|
|
43
|
+
* the buttons spec page's XS, S, M, L and XL, each with its own padding
|
|
44
|
+
* and type role. `md` is the page's default. The height is a floor, so a
|
|
45
|
+
* label that wraps, or that the device's text size enlarges, grows the
|
|
46
|
+
* button rather than running out of it.
|
|
47
|
+
* @default 'md'
|
|
48
|
+
*/
|
|
49
|
+
readonly size?: ButtonSize;
|
|
50
|
+
readonly style?: StyleProp<ViewStyle>;
|
|
51
|
+
/**
|
|
52
|
+
* How much weight the button pulls. `filled` and `tonal` carry a container
|
|
53
|
+
* of their own; `outlined` and `text` sit on the page; `elevated` sits on
|
|
54
|
+
* a low surface and lifts off it with a shadow, for a button that has to
|
|
55
|
+
* separate from a busy background rather than from the page.
|
|
56
|
+
* @default 'filled'
|
|
57
|
+
*/
|
|
58
|
+
readonly variant?: ButtonVariant;
|
|
59
|
+
};
|
|
60
|
+
type ButtonShape = 'round' | 'square';
|
|
61
|
+
type ButtonSize = 'lg' | 'md' | 'xl' | 'xs' | 'xxl';
|
|
62
|
+
type ButtonVariant = 'elevated' | 'filled' | 'outlined' | 'text' | 'tonal';
|
|
63
|
+
/**
|
|
64
|
+
* The design's button, at five emphasis levels and five control heights,
|
|
65
|
+
* round or square, with web's props and values. Given `href` it is a link with
|
|
66
|
+
* the same appearance, and given `isSelected`, `defaultSelected` or
|
|
67
|
+
* `onChange` it is a toggle, which reports its state to a screen reader and
|
|
68
|
+
* draws the page's second pair of colour roles for its variant.
|
|
69
|
+
*
|
|
70
|
+
* ```tsx
|
|
71
|
+
* <Button defaultSelected variant="tonal">
|
|
72
|
+
* Label
|
|
73
|
+
* </Button>
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* A column stretches a button across it, as it does any view, and as a flex
|
|
77
|
+
* column does a button on web; a column that should hold its buttons at their
|
|
78
|
+
* labels' width says so with `alignItems`.
|
|
79
|
+
*
|
|
80
|
+
* The two sizes under 48dp tall, `xs` and `md`, take presses over a 48dp
|
|
81
|
+
* target through `hitSlop`, which a `hitSlop` of the call site's own replaces.
|
|
82
|
+
* `style`, `ref` and `testID` land on the `Pressable`.
|
|
83
|
+
*/
|
|
84
|
+
declare function Button({ children, defaultSelected, disableRipple, hitSlop: ownHitSlop, href, icon, isDisabled, isSelected, onBlur, onChange, onFocus, onHoverIn, onHoverOut, onLayout, onPress, onPressIn, onPressOut, shape, size, style, type, variant, ...props }: ButtonProps): import("react").JSX.Element;
|
|
85
|
+
//#endregion
|
|
86
|
+
export { Button, type ButtonProps, type ButtonShape, type ButtonSize, type ButtonVariant };
|
|
87
|
+
//# sourceMappingURL=index.d.ts.map
|