@ng-native/fabric 0.3.0 → 0.4.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,16 @@
1
+ /**
2
+ * The web's `aria-*` attributes as the props native reads, mapped as React Native's `View.js`
3
+ * maps them before a view's props reach native.
4
+ *
5
+ * An attribute is text, on any element that commits a view: the host of an app's own component
6
+ * has no input to take one, and a label that is dropped fails silently for exactly the people who
7
+ * cannot see that it is missing. A prop the element already has is its own answer and is left:
8
+ * the primitives of `@ng-native/components` take these as inputs and write the props themselves.
9
+ */
10
+ type Props = Record<string, unknown>;
11
+ /**
12
+ * Writes into `props` what the `aria-*` attributes among `attributes` say, wherever `props` does
13
+ * not say it already.
14
+ */
15
+ export declare function applyAria(attributes: Props, props: Props): void;
16
+ export {};
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The web's `aria-*` attributes as the props native reads, mapped as React Native's `View.js`
3
+ * maps them before a view's props reach native.
4
+ *
5
+ * An attribute is text, on any element that commits a view: the host of an app's own component
6
+ * has no input to take one, and a label that is dropped fails silently for exactly the people who
7
+ * cannot see that it is missing. A prop the element already has is its own answer and is left:
8
+ * the primitives of `@ng-native/components` take these as inputs and write the props themselves.
9
+ */
10
+ /** `'true'` and `'false'` as the booleans they say; anything else, `mixed` included, as written. */
11
+ const flag = (value) => value === 'true' || value === '' ? true : value === 'false' ? false : value;
12
+ /** Text as the number it says, and nothing where it says none: `NaN` is no value to send. */
13
+ const number = (value) => {
14
+ if (typeof value !== 'string')
15
+ return value;
16
+ const said = value.trim() === '' ? NaN : Number(value);
17
+ return Number.isFinite(said) ? said : undefined;
18
+ };
19
+ /** The attributes that are one prop each, with how the value is read. */
20
+ const ONE_TO_ONE = {
21
+ 'aria-label': ['accessibilityLabel', (value) => value],
22
+ 'aria-labelledby': [
23
+ 'accessibilityLabelledBy',
24
+ (value) => (typeof value === 'string' ? value.split(/\s*,\s*/) : value),
25
+ ],
26
+ 'aria-live': ['accessibilityLiveRegion', (value) => (value === 'off' ? 'none' : value)],
27
+ 'aria-hidden': ['accessibilityElementsHidden', flag],
28
+ 'aria-modal': ['accessibilityViewIsModal', flag],
29
+ };
30
+ /** The attributes gathered into `accessibilityState`, by the key each is there. */
31
+ const STATE = {
32
+ 'aria-busy': 'busy',
33
+ 'aria-checked': 'checked',
34
+ 'aria-disabled': 'disabled',
35
+ 'aria-expanded': 'expanded',
36
+ 'aria-selected': 'selected',
37
+ };
38
+ /** The attributes gathered into `accessibilityValue`. */
39
+ const VALUE = {
40
+ 'aria-valuemax': 'max',
41
+ 'aria-valuemin': 'min',
42
+ 'aria-valuenow': 'now',
43
+ 'aria-valuetext': 'text',
44
+ };
45
+ /** `attributes` gathered into one object by `keys`, or undefined when it has none of them. */
46
+ function gathered(attributes, keys, read) {
47
+ let out;
48
+ for (const attribute of Object.keys(keys)) {
49
+ const value = attributes[attribute];
50
+ const said = value === undefined || value === null ? undefined : read(keys[attribute], value);
51
+ if (said !== undefined)
52
+ (out ??= {})[keys[attribute]] = said;
53
+ }
54
+ return out;
55
+ }
56
+ /**
57
+ * Writes into `props` what the `aria-*` attributes among `attributes` say, wherever `props` does
58
+ * not say it already.
59
+ */
60
+ export function applyAria(attributes, props) {
61
+ for (const attribute of Object.keys(ONE_TO_ONE)) {
62
+ const value = attributes[attribute];
63
+ const [prop, read] = ONE_TO_ONE[attribute];
64
+ if (value !== undefined && value !== null && props[prop] === undefined)
65
+ props[prop] = read(value);
66
+ }
67
+ // As `View.js`: a hidden element takes what is inside it out of the accessibility tree on
68
+ // Android too, which has no prop of its own for that.
69
+ if (flag(attributes['aria-hidden']) === true)
70
+ props['importantForAccessibility'] ??= 'no-hide-descendants';
71
+ const state = gathered(attributes, STATE, (_, value) => flag(value));
72
+ if (state)
73
+ props['accessibilityState'] ??= state;
74
+ const value = gathered(attributes, VALUE, (key, part) => (key === 'text' ? part : number(part)));
75
+ if (value)
76
+ props['accessibilityValue'] ??= value;
77
+ }
78
+ //# sourceMappingURL=aria-props.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aria-props.js","sourceRoot":"","sources":["../src/aria-props.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The web's `aria-*` attributes as the props native reads, mapped as React Native's `View.js`\n * maps them before a view's props reach native.\n *\n * An attribute is text, on any element that commits a view: the host of an app's own component\n * has no input to take one, and a label that is dropped fails silently for exactly the people who\n * cannot see that it is missing. A prop the element already has is its own answer and is left:\n * the primitives of `@ng-native/components` take these as inputs and write the props themselves.\n */\n\ntype Props = Record<string, unknown>;\n\n/** `'true'` and `'false'` as the booleans they say; anything else, `mixed` included, as written. */\nconst flag = (value: unknown): unknown =>\n value === 'true' || value === '' ? true : value === 'false' ? false : value;\n\n/** Text as the number it says, and nothing where it says none: `NaN` is no value to send. */\nconst number = (value: unknown): unknown => {\n if (typeof value !== 'string') return value;\n const said = value.trim() === '' ? NaN : Number(value);\n return Number.isFinite(said) ? said : undefined;\n};\n\n/** The attributes that are one prop each, with how the value is read. */\nconst ONE_TO_ONE: Readonly<\n Record<string, readonly [prop: string, read: (value: unknown) => unknown]>\n> = {\n 'aria-label': ['accessibilityLabel', (value) => value],\n 'aria-labelledby': [\n 'accessibilityLabelledBy',\n (value) => (typeof value === 'string' ? value.split(/\\s*,\\s*/) : value),\n ],\n 'aria-live': ['accessibilityLiveRegion', (value) => (value === 'off' ? 'none' : value)],\n 'aria-hidden': ['accessibilityElementsHidden', flag],\n 'aria-modal': ['accessibilityViewIsModal', flag],\n};\n\n/** The attributes gathered into `accessibilityState`, by the key each is there. */\nconst STATE: Readonly<Record<string, string>> = {\n 'aria-busy': 'busy',\n 'aria-checked': 'checked',\n 'aria-disabled': 'disabled',\n 'aria-expanded': 'expanded',\n 'aria-selected': 'selected',\n};\n\n/** The attributes gathered into `accessibilityValue`. */\nconst VALUE: Readonly<Record<string, string>> = {\n 'aria-valuemax': 'max',\n 'aria-valuemin': 'min',\n 'aria-valuenow': 'now',\n 'aria-valuetext': 'text',\n};\n\n/** `attributes` gathered into one object by `keys`, or undefined when it has none of them. */\nfunction gathered(\n attributes: Props,\n keys: Readonly<Record<string, string>>,\n read: (key: string, value: unknown) => unknown,\n): Props | undefined {\n let out: Props | undefined;\n for (const attribute of Object.keys(keys)) {\n const value = attributes[attribute];\n const said = value === undefined || value === null ? undefined : read(keys[attribute]!, value);\n if (said !== undefined) (out ??= {})[keys[attribute]!] = said;\n }\n return out;\n}\n\n/**\n * Writes into `props` what the `aria-*` attributes among `attributes` say, wherever `props` does\n * not say it already.\n */\nexport function applyAria(attributes: Props, props: Props): void {\n for (const attribute of Object.keys(ONE_TO_ONE)) {\n const value = attributes[attribute];\n const [prop, read] = ONE_TO_ONE[attribute]!;\n if (value !== undefined && value !== null && props[prop] === undefined)\n props[prop] = read(value);\n }\n // As `View.js`: a hidden element takes what is inside it out of the accessibility tree on\n // Android too, which has no prop of its own for that.\n if (flag(attributes['aria-hidden']) === true)\n props['importantForAccessibility'] ??= 'no-hide-descendants';\n const state = gathered(attributes, STATE, (_, value) => flag(value));\n if (state) props['accessibilityState'] ??= state;\n const value = gathered(attributes, VALUE, (key, part) => (key === 'text' ? part : number(part)));\n if (value) props['accessibilityValue'] ??= value;\n}\n"]}
package/dist/css.d.ts CHANGED
@@ -59,11 +59,18 @@ export interface StyleRule {
59
59
  /** Between compounds; length is `compounds.length - 1`. */
60
60
  readonly combinators: readonly Combinator[];
61
61
  readonly specificity: number;
62
+ /**
63
+ * The cascade layer the rule is in, as its place in its sheet's `layers`, or nothing for a rule
64
+ * in no layer, which beats every layered one whatever their specificity.
65
+ */
66
+ readonly layer?: number;
62
67
  readonly order: number;
63
68
  readonly declarations: Readonly<Record<string, unknown>>;
64
69
  readonly important?: Readonly<Record<string, unknown>>;
65
70
  /** Custom properties this rule defines, pre-converted into every form a use site might want. */
66
71
  readonly tokens?: Readonly<Record<string, TokenValue>>;
72
+ /** The names among `tokens` declared `!important`, which beat every plain one. */
73
+ readonly importantTokens?: readonly string[];
67
74
  /** Declarations whose value is a `var()`, resolved once the token map is known. */
68
75
  readonly deferred?: readonly DeferredDeclaration[];
69
76
  /** The media query guarding this rule, if any. */
@@ -186,6 +193,8 @@ export interface DeferredDeclaration {
186
193
  * unambiguous given a single-valued token, so `padding: var(--gap)` writes all four.
187
194
  */
188
195
  readonly props: readonly string[];
196
+ /** The element a bound declaration is on, by name, for a message about it to say. */
197
+ readonly on?: string;
189
198
  /** A `var()` reference. Exactly one of this and `compute` is present. */
190
199
  readonly kind?: TokenKind;
191
200
  readonly reference?: string;
@@ -284,6 +293,8 @@ export interface LineTemplate {
284
293
  readonly roles: readonly ('width' | 'style' | 'color')[];
285
294
  readonly widths: readonly string[];
286
295
  readonly colors: readonly string[];
296
+ /** `color-mix(in srgb, var(--tint) 35%, transparent)`: the colour, written as a function. */
297
+ readonly colour?: unknown;
287
298
  readonly style?: string;
288
299
  }
289
300
  /**
@@ -363,6 +374,12 @@ export interface GradientTemplate {
363
374
  }
364
375
  export interface StyleSheet {
365
376
  readonly rules: readonly StyleRule[];
377
+ /**
378
+ * The sheet's cascade layers, each by its name from the outermost layer in, in the order they
379
+ * were first named. A name that starts with a null is a block with no name, which is a layer
380
+ * no other block can name.
381
+ */
382
+ readonly layers?: readonly (readonly string[])[];
366
383
  /**
367
384
  * `@keyframes` by name. Global within a sheet, as they are within a document; the engine keeps
368
385
  * one registry across every sheet it sees, so a name defined in a global stylesheet is usable
@@ -386,6 +403,8 @@ export interface StyleSheet {
386
403
  readonly family: string;
387
404
  readonly source: unknown;
388
405
  readonly weight?: number;
406
+ /** The weights a variable font covers, `font-weight: 100 900`, in place of one `weight`. */
407
+ readonly weightRange?: readonly [number, number];
389
408
  readonly style?: string;
390
409
  }[];
391
410
  }
@@ -432,6 +451,20 @@ export interface StyleTarget {
432
451
  readonly kind?: string;
433
452
  readonly classes: ReadonlySet<string> | null;
434
453
  readonly props: Readonly<Record<string, unknown>>;
454
+ /**
455
+ * Whether `props.style` sets a property children inherit, kept by whoever sets the style so the
456
+ * resolver reads the style only where it can matter. Absent is false.
457
+ */
458
+ readonly inlineInherits?: boolean;
459
+ /**
460
+ * The bound declarations that are a `var()`, `[style.color]="'var(--brand)'"`, as the deferred
461
+ * declarations a rule's would be: settled with the node's tokens, last of its normal ones.
462
+ */
463
+ readonly boundStyle?: readonly DeferredDeclaration[] | null;
464
+ /** A node the engine made, such as the paragraph around loose text: it only inherits. */
465
+ readonly anonymous?: true;
466
+ /** One of HTML's text elements the engine has styles of its own for, such as `strong`. */
467
+ readonly styled?: true;
435
468
  /**
436
469
  * The sheet this node's own rules come from, which is the sheet of the component whose renderer
437
470
  * created it. Read from the node rather than passed in, because a node's ancestors usually
@@ -521,6 +554,14 @@ export declare function indexRules(entries: readonly RuleEntry[]): RuleIndex;
521
554
  * lists are short by construction, which is the entire point of the index.
522
555
  */
523
556
  export declare function candidateRules(node: StyleTarget, index: RuleIndex): RuleEntry[];
557
+ /** Whether an inline style sets a property children inherit. Allocates nothing: it runs per set. */
558
+ export declare function setsInherited(style: unknown): boolean;
559
+ /**
560
+ * The inherited properties a node's inline style sets, or null for none. Inline style is the
561
+ * strongest normal declaration on its element, so what it sets is inherited, and read by
562
+ * `color: inherit` and `currentColor`, as a rule's would be.
563
+ */
564
+ export declare function inlineInherited(style: unknown): Record<string, unknown> | null;
524
565
  /**
525
566
  * The runtime half of CSS for one engine: the global sheet, the conditions media queries are
526
567
  * evaluated against, and the memo that makes resolution cost nodes x rules rather than
@@ -558,6 +599,21 @@ export declare class StyleResolver {
558
599
  * single index.
559
600
  */
560
601
  private merged;
602
+ /**
603
+ * Whether any sheet merged so far has a rule in a cascade layer. Until one does, rules are
604
+ * ordered by weight alone and the cascade does not look for layers, which is nearly every app.
605
+ * It stays set once a layered sheet has gone, which costs a look at each cascade and no more.
606
+ */
607
+ private layered;
608
+ /**
609
+ * Every layer the sheets seen so far have named, in the order each name was first seen, which
610
+ * is the one order a document has for them. A name keeps its place when its sheet is replaced.
611
+ */
612
+ private readonly layerNames;
613
+ /** Each layered rule's place among them, set when its sheet is first merged. */
614
+ private readonly layerPlaces;
615
+ private readonly layeredSheets;
616
+ private unnamedLayers;
561
617
  /**
562
618
  * The application-level sheet, if any: the one set of rules allowed to match a node whatever
563
619
  * component created it, which is what resets, utility classes and `:root` tokens all need.
@@ -584,7 +640,7 @@ export declare class StyleResolver {
584
640
  * Told of a `var()` that names a custom property nothing in scope defines and has no fallback,
585
641
  * which is dropped. Set only in development, where it is how the engine says so.
586
642
  */
587
- onUndefinedToken: ((name: string, props: readonly string[]) => void) | null;
643
+ onUndefinedToken: ((name: string, props: readonly string[], on?: string) => void) | null;
588
644
  /**
589
645
  * Told of a `display: var()` whose token holds no display native has, `grid` or `table`, which
590
646
  * leaves display unset. Set only in development, where it is how the engine says so: the
@@ -658,6 +714,12 @@ export declare class StyleResolver {
658
714
  * it, so it loses to their extra attribute and wins a tie with them.
659
715
  */
660
716
  private merge;
717
+ /**
718
+ * Gives each of a sheet's layers its place among every sheet's, the first time the sheet is
719
+ * merged, and each of its layered rules that place. Sheets are merged in the order a document
720
+ * holds them: the app's global sheet, then each component's as it first renders.
721
+ */
722
+ private placeLayers;
661
723
  /**
662
724
  * A node's style from the rules it matched, shared with every other node that matched the same
663
725
  * rules under the same inherited values and tokens: a list's rows, and what is inside each.
@@ -722,6 +784,16 @@ export declare class StyleResolver {
722
784
  /** A length relative to the viewport or to the font size in scope. */
723
785
  private computed;
724
786
  }
787
+ /**
788
+ * A bound declaration whose value is one `var()`, `var(--brand, red)`, as the deferred declaration
789
+ * the compiler writes for the same value in a rule. `token` is the value as a token, which is an
790
+ * alias when it is a `var()`; null for any other.
791
+ *
792
+ * ponytail: the whole value has to be the `var()`. One inside a longer value, `calc()` included,
793
+ * is what the compiler parses at build time and nothing here does; write the sum in a custom
794
+ * property, `[style.--gap]`, and read that in the stylesheet.
795
+ */
796
+ export declare function boundDeclaration(prop: string, token: TokenValue | undefined, on?: string): DeferredDeclaration | null;
725
797
  /** `hsl()` reads a channels token as hue, saturation and lightness; `rgb()` as sRGB. */
726
798
  type ChannelSpace = 'rgb' | 'hsl';
727
799
  /**