fontdue-js 3.0.5 → 3.1.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.
- package/CHANGELOG.md +14 -0
- package/dist/__generated__/FeatureTesterCard_fontStyle.graphql.d.ts +23 -0
- package/dist/__generated__/FeatureTesterCard_fontStyle.graphql.js +62 -0
- package/dist/__generated__/FeatureTesterStandaloneQuery.graphql.d.ts +25 -0
- package/dist/__generated__/FeatureTesterStandaloneQuery.graphql.js +240 -0
- package/dist/__generated__/FeatureTestersIdQuery.graphql.d.ts +21 -0
- package/dist/__generated__/FeatureTestersIdQuery.graphql.js +344 -0
- package/dist/__generated__/FeatureTestersSlugQuery.graphql.d.ts +25 -0
- package/dist/__generated__/FeatureTestersSlugQuery.graphql.js +364 -0
- package/dist/__generated__/FeatureTesters_collection.graphql.d.ts +39 -0
- package/dist/__generated__/FeatureTesters_collection.graphql.js +145 -0
- package/dist/__generated__/NodePasswordFormAccessNodeMutation.graphql.d.ts +2 -1
- package/dist/__generated__/NodePasswordFormAccessNodeMutation.graphql.js +10 -4
- package/dist/__generated__/NodePasswordFormElementIDQuery.graphql.d.ts +21 -0
- package/dist/__generated__/NodePasswordFormElementIDQuery.graphql.js +86 -0
- package/dist/__generated__/NodePasswordFormElementSlugQuery.graphql.d.ts +25 -0
- package/dist/__generated__/NodePasswordFormElementSlugQuery.graphql.js +108 -0
- package/dist/__generated__/TypeTestersIDQuery.graphql.d.ts +1 -1
- package/dist/__generated__/TypeTestersIDQuery.graphql.js +9 -3
- package/dist/__generated__/TypeTestersRefetchQuery.graphql.d.ts +1 -1
- package/dist/__generated__/TypeTestersRefetchQuery.graphql.js +10 -4
- package/dist/__generated__/TypeTestersSlugQuery.graphql.d.ts +1 -1
- package/dist/__generated__/TypeTestersSlugQuery.graphql.js +9 -3
- package/dist/__generated__/TypeTesters_collection.graphql.d.ts +2 -1
- package/dist/__generated__/TypeTesters_collection.graphql.js +8 -2
- package/dist/__tests__/createFontdueFetch.test.js +128 -4
- package/dist/__tests__/highlight.test.js +141 -0
- package/dist/__tests__/middleware.test.js +132 -0
- package/dist/components/FeatureTester/FeatureTesterCard.d.ts +30 -0
- package/dist/components/FeatureTester/FeatureTesterCard.js +167 -0
- package/dist/components/FeatureTester/FeatureTesterElement.d.ts +19 -0
- package/dist/components/FeatureTester/FeatureTesterElement.js +42 -0
- package/dist/components/FeatureTester/FeatureTesters.d.ts +43 -0
- package/dist/components/FeatureTester/FeatureTesters.js +156 -0
- package/dist/components/FeatureTester/FeatureTesters.server.d.ts +9 -0
- package/dist/components/FeatureTester/FeatureTesters.server.js +40 -0
- package/dist/components/FeatureTester/FeatureTestersElement.d.ts +10 -0
- package/dist/components/FeatureTester/FeatureTestersElement.js +27 -0
- package/dist/components/FeatureTester/highlight.d.ts +19 -0
- package/dist/components/FeatureTester/highlight.js +71 -0
- package/dist/components/FeatureTester/index.d.ts +26 -0
- package/dist/components/FeatureTester/index.js +66 -0
- package/dist/components/FeatureTester/index.server.d.ts +7 -0
- package/dist/components/FeatureTester/index.server.js +30 -0
- package/dist/components/NodePasswordForm/NodePasswordFormElement.d.ts +3 -0
- package/dist/components/NodePasswordForm/NodePasswordFormElement.js +65 -0
- package/dist/components/NodePasswordForm/index.d.ts +16 -1
- package/dist/components/NodePasswordForm/index.js +30 -59
- package/dist/components/Root/index.js +2 -1
- package/dist/components/TypeTesters/index.js +5 -1
- package/dist/fontdue.css +145 -0
- package/dist/hooks/useFeatureTesterAutofit.d.ts +17 -0
- package/dist/hooks/useFeatureTesterAutofit.js +106 -0
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +16 -1
- package/dist/next/registerSingleTenantResolver.js +13 -1
- package/dist/next/tenant.d.ts +1 -0
- package/dist/next/tenant.js +27 -2
- package/dist/nodeAccess.d.ts +18 -0
- package/dist/nodeAccess.js +84 -0
- package/dist/preview/server.d.ts +1 -20
- package/dist/preview/server.js +16 -85
- package/dist/relay/environment.js +8 -2
- package/dist/relay/serverConfig.d.ts +3 -0
- package/dist/relay/serverConfig.js +22 -1
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.js +90 -7
- package/dist/server/middleware.d.ts +37 -0
- package/dist/server/middleware.js +144 -0
- package/package.json +8 -2
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
4
|
+
import _FeatureTestersSlugQuery from "../../__generated__/FeatureTestersSlugQuery.graphql.js";
|
|
5
|
+
import _FeatureTestersIdQuery from "../../__generated__/FeatureTestersIdQuery.graphql.js";
|
|
6
|
+
import _FeatureTesters_collection from "../../__generated__/FeatureTesters_collection.graphql.js";
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { graphql, useFragment, useLazyLoadQuery, usePreloadedQuery } from 'react-relay';
|
|
9
|
+
import FeatureTesterCard from './FeatureTesterCard.js';
|
|
10
|
+
import { EnsureFontdueContext } from '../FontdueContextProvider/index.js';
|
|
11
|
+
import FeatureTestersIdQueryNode from '../../__generated__/FeatureTestersIdQuery.graphql.js';
|
|
12
|
+
import FeatureTestersSlugQueryNode from '../../__generated__/FeatureTestersSlugQuery.graphql.js';
|
|
13
|
+
import loadSerializableQuery from '../../relay/loadSerializableQuery.js';
|
|
14
|
+
import useSerializablePreloadedQuery from '../../relay/useSerializablePreloadedQuery.js';
|
|
15
|
+
const collectionFragment = (_FeatureTesters_collection.hash && _FeatureTesters_collection.hash !== "933c122b193ca5df430509d87e9c4e1d" && console.error("The definition of 'FeatureTesters_collection' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _FeatureTesters_collection);
|
|
16
|
+
function FeatureTestersList(_ref) {
|
|
17
|
+
let {
|
|
18
|
+
collection,
|
|
19
|
+
highlightColor,
|
|
20
|
+
toggle,
|
|
21
|
+
autofit
|
|
22
|
+
} = _ref;
|
|
23
|
+
const data = useFragment(collectionFragment, collection);
|
|
24
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, data.featureTesters.map(ft => ft.fontStyle ? /*#__PURE__*/React.createElement(FeatureTesterCard, {
|
|
25
|
+
key: ft.id,
|
|
26
|
+
fontStyle: ft.fontStyle,
|
|
27
|
+
feature: ft.feature,
|
|
28
|
+
label: ft.label ?? undefined,
|
|
29
|
+
content: ft.content,
|
|
30
|
+
fontSize: ft.size != null ? Number(ft.size) : undefined,
|
|
31
|
+
lineHeight: ft.lineHeight != null ? Number(ft.lineHeight) : undefined,
|
|
32
|
+
alignment: ft.alignment === 'left' || ft.alignment === 'center' || ft.alignment === 'right' ? ft.alignment : undefined,
|
|
33
|
+
defaultOn: data.featureTesterDefaultOn,
|
|
34
|
+
changedRanges: ft.changedRanges,
|
|
35
|
+
variableSettings: ft.variableSettings,
|
|
36
|
+
highlightColor: highlightColor,
|
|
37
|
+
toggle: toggle,
|
|
38
|
+
autofit: autofit ?? ft.autofit,
|
|
39
|
+
showTag: data.featureTesterShowTag
|
|
40
|
+
}) : null));
|
|
41
|
+
}
|
|
42
|
+
const idQuery = (_FeatureTestersIdQuery.hash && _FeatureTestersIdQuery.hash !== "55f152ae85db4ebafd21ff7945f4079a" && console.error("The definition of 'FeatureTestersIdQuery' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _FeatureTestersIdQuery);
|
|
43
|
+
const slugQuery = (_FeatureTestersSlugQuery.hash && _FeatureTestersSlugQuery.hash !== "726fca18c4a30ca9dd8f5aaf074c8139" && console.error("The definition of 'FeatureTestersSlugQuery' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _FeatureTestersSlugQuery);
|
|
44
|
+
function ById(_ref2) {
|
|
45
|
+
let {
|
|
46
|
+
collectionId,
|
|
47
|
+
...rest
|
|
48
|
+
} = _ref2;
|
|
49
|
+
const data = useLazyLoadQuery(idQuery, {
|
|
50
|
+
id: collectionId
|
|
51
|
+
});
|
|
52
|
+
return data.node ? /*#__PURE__*/React.createElement(FeatureTestersList, _extends({
|
|
53
|
+
collection: data.node
|
|
54
|
+
}, rest)) : null;
|
|
55
|
+
}
|
|
56
|
+
function BySlug(_ref3) {
|
|
57
|
+
var _data$viewer, _data$viewer$slug;
|
|
58
|
+
let {
|
|
59
|
+
collectionSlug,
|
|
60
|
+
...rest
|
|
61
|
+
} = _ref3;
|
|
62
|
+
const data = useLazyLoadQuery(slugQuery, {
|
|
63
|
+
slug: collectionSlug
|
|
64
|
+
});
|
|
65
|
+
const coll = (_data$viewer = data.viewer) === null || _data$viewer === void 0 ? void 0 : (_data$viewer$slug = _data$viewer.slug) === null || _data$viewer$slug === void 0 ? void 0 : _data$viewer$slug.fontCollection;
|
|
66
|
+
return coll ? /*#__PURE__*/React.createElement(FeatureTestersList, _extends({
|
|
67
|
+
collection: coll
|
|
68
|
+
}, rest)) : null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---- Server-preload path (RSC): the server awaits the query and hands the
|
|
72
|
+
// serialized response to these client renderers, which commit it into the store
|
|
73
|
+
// so `usePreloadedQuery` resolves synchronously on the client (no refetch on
|
|
74
|
+
// hydration). Mirrors CharacterViewer.
|
|
75
|
+
|
|
76
|
+
export async function loadFeatureTestersQuery(variables, options) {
|
|
77
|
+
if (variables.collectionId) {
|
|
78
|
+
return loadSerializableQuery(FeatureTestersIdQueryNode, {
|
|
79
|
+
id: variables.collectionId
|
|
80
|
+
}, options);
|
|
81
|
+
}
|
|
82
|
+
if (variables.collectionSlug) {
|
|
83
|
+
return loadSerializableQuery(FeatureTestersSlugQueryNode, {
|
|
84
|
+
slug: variables.collectionSlug
|
|
85
|
+
}, options);
|
|
86
|
+
}
|
|
87
|
+
throw new Error('loadFeatureTestersQuery expected either collectionId or collectionSlug');
|
|
88
|
+
}
|
|
89
|
+
export function FeatureTestersPreloadedIDQueryRenderer(_ref4) {
|
|
90
|
+
let {
|
|
91
|
+
preloadedQuery,
|
|
92
|
+
...options
|
|
93
|
+
} = _ref4;
|
|
94
|
+
const queryRef = useSerializablePreloadedQuery(preloadedQuery, 'store-or-network', idQuery);
|
|
95
|
+
const data = usePreloadedQuery(idQuery, queryRef);
|
|
96
|
+
return data.node ? /*#__PURE__*/React.createElement(FeatureTestersList, _extends({
|
|
97
|
+
collection: data.node
|
|
98
|
+
}, options)) : null;
|
|
99
|
+
}
|
|
100
|
+
export function FeatureTestersPreloadedSlugQueryRenderer(_ref5) {
|
|
101
|
+
var _data$viewer2, _data$viewer2$slug;
|
|
102
|
+
let {
|
|
103
|
+
preloadedQuery,
|
|
104
|
+
...options
|
|
105
|
+
} = _ref5;
|
|
106
|
+
const queryRef = useSerializablePreloadedQuery(preloadedQuery, 'store-or-network', slugQuery);
|
|
107
|
+
const data = usePreloadedQuery(slugQuery, queryRef);
|
|
108
|
+
const coll = (_data$viewer2 = data.viewer) === null || _data$viewer2 === void 0 ? void 0 : (_data$viewer2$slug = _data$viewer2.slug) === null || _data$viewer2$slug === void 0 ? void 0 : _data$viewer2$slug.fontCollection;
|
|
109
|
+
return coll ? /*#__PURE__*/React.createElement(FeatureTestersList, _extends({
|
|
110
|
+
collection: coll
|
|
111
|
+
}, options)) : null;
|
|
112
|
+
}
|
|
113
|
+
function FeatureTestersPreloadedRenderer(_ref6) {
|
|
114
|
+
let {
|
|
115
|
+
preloadedQuery,
|
|
116
|
+
...options
|
|
117
|
+
} = _ref6;
|
|
118
|
+
if (preloadedQuery.params.name === 'FeatureTestersIdQuery') {
|
|
119
|
+
return /*#__PURE__*/React.createElement(FeatureTestersPreloadedIDQueryRenderer, _extends({
|
|
120
|
+
preloadedQuery: preloadedQuery
|
|
121
|
+
}, options));
|
|
122
|
+
}
|
|
123
|
+
return /*#__PURE__*/React.createElement(FeatureTestersPreloadedSlugQueryRenderer, _extends({
|
|
124
|
+
preloadedQuery: preloadedQuery
|
|
125
|
+
}, options));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Renders every Feature Tester card a tenant has configured on a font
|
|
129
|
+
// collection. Accepts a preloaded query (server-side preload path — Astro/RR7
|
|
130
|
+
// frontmatter or a manual loader call) or `{collectionId}`/`{collectionSlug}`
|
|
131
|
+
// for lazy fetch.
|
|
132
|
+
export default function FeatureTesters(_ref7) {
|
|
133
|
+
let {
|
|
134
|
+
config,
|
|
135
|
+
...props
|
|
136
|
+
} = _ref7;
|
|
137
|
+
const {
|
|
138
|
+
highlightColor,
|
|
139
|
+
toggle,
|
|
140
|
+
autofit
|
|
141
|
+
} = props;
|
|
142
|
+
const options = {
|
|
143
|
+
highlightColor,
|
|
144
|
+
toggle,
|
|
145
|
+
autofit
|
|
146
|
+
};
|
|
147
|
+
return /*#__PURE__*/React.createElement(EnsureFontdueContext, {
|
|
148
|
+
config: config
|
|
149
|
+
}, 'preloadedQuery' in props && props.preloadedQuery ? /*#__PURE__*/React.createElement(FeatureTestersPreloadedRenderer, _extends({
|
|
150
|
+
preloadedQuery: props.preloadedQuery
|
|
151
|
+
}, options)) : 'collectionId' in props && props.collectionId ? /*#__PURE__*/React.createElement(ById, _extends({
|
|
152
|
+
collectionId: props.collectionId
|
|
153
|
+
}, options)) : /*#__PURE__*/React.createElement(BySlug, _extends({
|
|
154
|
+
collectionSlug: props.collectionSlug
|
|
155
|
+
}, options)));
|
|
156
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FeatureTestersProps } from './FeatureTesters.js';
|
|
3
|
+
export type { FeatureTestersPreloadedQuery } from './FeatureTesters.js';
|
|
4
|
+
export declare function loadFeatureTestersQuery(): never;
|
|
5
|
+
export default function FeatureTesters({ collectionId, collectionSlug, ...rest }: Extract<FeatureTestersProps, {
|
|
6
|
+
collectionId: string;
|
|
7
|
+
} | {
|
|
8
|
+
collectionSlug: string;
|
|
9
|
+
}>): Promise<React.JSX.Element | null>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import loadSerializableQuery from '../../relay/loadSerializableQuery.js';
|
|
4
|
+
import { FeatureTestersPreloadedIDQueryRenderer, FeatureTestersPreloadedSlugQueryRenderer } from './FeatureTesters.js';
|
|
5
|
+
import FeatureTestersIdQueryNode from '../../__generated__/FeatureTestersIdQuery.graphql.js';
|
|
6
|
+
import FeatureTestersSlugQueryNode from '../../__generated__/FeatureTestersSlugQuery.graphql.js';
|
|
7
|
+
// Stub for the RSC export condition. See FontdueProvider/index.server.tsx
|
|
8
|
+
// for the rationale.
|
|
9
|
+
export function loadFeatureTestersQuery() {
|
|
10
|
+
throw new Error("loadFeatureTestersQuery isn't needed in React Server Components — " + 'the <FeatureTesters> server entrypoint awaits its query automatically. ' + 'Drop the manual call.');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Next RSC variant: awaits the query on the server and hands the response to
|
|
14
|
+
// the client `*PreloadedQueryRenderer`. Lets pages just write
|
|
15
|
+
// `<FeatureTesters collectionSlug="..." />` in an RSC without manually invoking
|
|
16
|
+
// `loadFeatureTestersQuery` + threading `preloadedQuery` through props.
|
|
17
|
+
export default async function FeatureTesters(_ref) {
|
|
18
|
+
let {
|
|
19
|
+
collectionId,
|
|
20
|
+
collectionSlug,
|
|
21
|
+
...rest
|
|
22
|
+
} = _ref;
|
|
23
|
+
if (collectionId) {
|
|
24
|
+
const preloadedQuery = await loadSerializableQuery(FeatureTestersIdQueryNode, {
|
|
25
|
+
id: collectionId
|
|
26
|
+
});
|
|
27
|
+
return /*#__PURE__*/React.createElement(FeatureTestersPreloadedIDQueryRenderer, _extends({
|
|
28
|
+
preloadedQuery: preloadedQuery
|
|
29
|
+
}, rest));
|
|
30
|
+
}
|
|
31
|
+
if (collectionSlug) {
|
|
32
|
+
const preloadedQuery = await loadSerializableQuery(FeatureTestersSlugQueryNode, {
|
|
33
|
+
slug: collectionSlug
|
|
34
|
+
});
|
|
35
|
+
return /*#__PURE__*/React.createElement(FeatureTestersPreloadedSlugQueryRenderer, _extends({
|
|
36
|
+
preloadedQuery: preloadedQuery
|
|
37
|
+
}, rest));
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface FeatureTestersElement_props {
|
|
3
|
+
collectionId?: string;
|
|
4
|
+
collectionSlug?: string;
|
|
5
|
+
highlightColor?: string;
|
|
6
|
+
toggle?: string;
|
|
7
|
+
autofit?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const FeatureTestersElement: React.FC<FeatureTestersElement_props>;
|
|
10
|
+
export default FeatureTestersElement;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import FeatureTesters from './FeatureTesters.js';
|
|
4
|
+
const parseBool = (input, fallback) => input === undefined || input === '' ? fallback : input === 'true';
|
|
5
|
+
export const FeatureTestersElement = _ref => {
|
|
6
|
+
let {
|
|
7
|
+
collectionId,
|
|
8
|
+
collectionSlug,
|
|
9
|
+
highlightColor,
|
|
10
|
+
toggle,
|
|
11
|
+
autofit
|
|
12
|
+
} = _ref;
|
|
13
|
+
const shared = {
|
|
14
|
+
highlightColor: highlightColor || undefined,
|
|
15
|
+
// Only override the per-card dashboard settings when the attribute is
|
|
16
|
+
// actually present on the element; otherwise leave undefined so each card
|
|
17
|
+
// uses its own.
|
|
18
|
+
toggle: toggle === undefined ? undefined : toggle === 'hover' ? 'hover' : 'button',
|
|
19
|
+
autofit: autofit === undefined ? undefined : parseBool(autofit, false)
|
|
20
|
+
};
|
|
21
|
+
return collectionId ? /*#__PURE__*/React.createElement(FeatureTesters, _extends({
|
|
22
|
+
collectionId: collectionId
|
|
23
|
+
}, shared)) : /*#__PURE__*/React.createElement(FeatureTesters, _extends({
|
|
24
|
+
collectionSlug: collectionSlug || ''
|
|
25
|
+
}, shared));
|
|
26
|
+
};
|
|
27
|
+
export default FeatureTestersElement;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface GlyphNameEntry {
|
|
2
|
+
readonly characters: string;
|
|
3
|
+
readonly features?: readonly string[] | null;
|
|
4
|
+
}
|
|
5
|
+
export interface Segment {
|
|
6
|
+
text: string;
|
|
7
|
+
sensitive: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface Mark {
|
|
10
|
+
start: number;
|
|
11
|
+
end: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function sensitiveStringsForFeature(glyphNames: readonly GlyphNameEntry[] | null | undefined, feature: string): string[];
|
|
14
|
+
export interface SensitivityOptions {
|
|
15
|
+
autoStrings?: readonly string[];
|
|
16
|
+
addMarks?: readonly Mark[];
|
|
17
|
+
}
|
|
18
|
+
export declare function computeSensitivityFlags(content: string, opts: SensitivityOptions): boolean[];
|
|
19
|
+
export declare function segmentByFlags(content: string, flags: readonly boolean[]): Segment[];
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Decide which characters in a sample string are "sensitive" to an OpenType
|
|
2
|
+
// feature.
|
|
3
|
+
//
|
|
4
|
+
// Auto-detection: `FontStyle.glyphNames` lists `{ characters, features }` where
|
|
5
|
+
// `characters` is the INPUT string a feature substitutes (a single character
|
|
6
|
+
// for single substitutions like ss03/smcp, or a sequence for ligatures like
|
|
7
|
+
// dlig). "Which characters does feature X touch" is the set of `characters`
|
|
8
|
+
// whose `features` includes X. That static map only covers single + ligature
|
|
9
|
+
// substitutions; the exact set for any feature comes from the server's shaped
|
|
10
|
+
// diff (`changedRanges`), which FeatureTesterCard passes in as marks.
|
|
11
|
+
//
|
|
12
|
+
// Everything is computed as a boolean-per-codepoint array so the sources
|
|
13
|
+
// compose cleanly. A contiguous run of `true` becomes one highlight span, which
|
|
14
|
+
// keeps ligature clusters whole (we never split a cluster across spans).
|
|
15
|
+
|
|
16
|
+
// An inclusive code-point index range. FeatureTesterCard builds these from the
|
|
17
|
+
// server-materialized `changedRanges`.
|
|
18
|
+
|
|
19
|
+
// The de-duplicated set of input strings the feature substitutes.
|
|
20
|
+
export function sensitiveStringsForFeature(glyphNames, feature) {
|
|
21
|
+
if (!glyphNames) return [];
|
|
22
|
+
const set = new Set();
|
|
23
|
+
for (const g of glyphNames) {
|
|
24
|
+
if (g.characters && g.features && g.features.includes(feature)) {
|
|
25
|
+
set.add(g.characters);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return Array.from(set);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Set flags[i] = true for every occurrence of `value` (matched by code point).
|
|
32
|
+
function applyText(chars, value, flags) {
|
|
33
|
+
const seq = Array.from(value);
|
|
34
|
+
if (seq.length === 0) return;
|
|
35
|
+
for (let i = 0; i + seq.length <= chars.length; i++) {
|
|
36
|
+
if (seq.every((c, k) => chars[i + k] === c)) {
|
|
37
|
+
for (let k = 0; k < seq.length; k++) flags[i + k] = true;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function computeSensitivityFlags(content, opts) {
|
|
42
|
+
const chars = Array.from(content);
|
|
43
|
+
const flags = new Array(chars.length).fill(false);
|
|
44
|
+
if (opts.autoStrings) {
|
|
45
|
+
for (const value of opts.autoStrings) applyText(chars, value, flags);
|
|
46
|
+
}
|
|
47
|
+
if (opts.addMarks) {
|
|
48
|
+
for (const mark of opts.addMarks) {
|
|
49
|
+
for (let i = Math.max(0, mark.start); i <= mark.end && i < chars.length; i++) {
|
|
50
|
+
flags[i] = true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return flags;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Collapse a per-codepoint flag array into consecutive sensitive/non-sensitive
|
|
58
|
+
// runs (one highlight span each).
|
|
59
|
+
export function segmentByFlags(content, flags) {
|
|
60
|
+
const chars = Array.from(content);
|
|
61
|
+
const segments = [];
|
|
62
|
+
for (let i = 0; i < chars.length; i++) {
|
|
63
|
+
const sensitive = flags[i] ?? false;
|
|
64
|
+
const last = segments[segments.length - 1];
|
|
65
|
+
if (last && last.sensitive === sensitive) last.text += chars[i];else segments.push({
|
|
66
|
+
text: chars[i],
|
|
67
|
+
sensitive
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return segments;
|
|
71
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FeatureTesterCardOptions } from './FeatureTesterCard.js';
|
|
3
|
+
import { Config } from '../ConfigContext.js';
|
|
4
|
+
import { SerializablePreloadedQuery, type LoadQueryOptions } from '../../relay/loadSerializableQuery.js';
|
|
5
|
+
import { FeatureTesterStandaloneQuery } from '../../__generated__/FeatureTesterStandaloneQuery.graphql.js';
|
|
6
|
+
export type FeatureTesterPreloadedQuery = SerializablePreloadedQuery<FeatureTesterStandaloneQuery>;
|
|
7
|
+
export interface LoadFeatureTesterQueryVariables {
|
|
8
|
+
familyName: string;
|
|
9
|
+
styleName: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function loadFeatureTesterQuery(variables: LoadFeatureTesterQueryVariables, options?: LoadQueryOptions): Promise<FeatureTesterPreloadedQuery>;
|
|
12
|
+
export declare function FeatureTesterPreloadedRenderer({ preloadedQuery, ...rest }: FeatureTesterCardOptions & {
|
|
13
|
+
preloadedQuery: FeatureTesterPreloadedQuery;
|
|
14
|
+
}): React.JSX.Element;
|
|
15
|
+
export type FeatureTesterProps = FeatureTesterCardOptions & {
|
|
16
|
+
config?: Config;
|
|
17
|
+
} & ({
|
|
18
|
+
preloadedQuery: FeatureTesterPreloadedQuery;
|
|
19
|
+
familyName?: never;
|
|
20
|
+
styleName?: never;
|
|
21
|
+
} | {
|
|
22
|
+
preloadedQuery?: never;
|
|
23
|
+
familyName: string;
|
|
24
|
+
styleName: string;
|
|
25
|
+
});
|
|
26
|
+
export default function FeatureTester(props: FeatureTesterProps): React.JSX.Element;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
4
|
+
import _FeatureTesterStandaloneQuery from "../../__generated__/FeatureTesterStandaloneQuery.graphql.js";
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { graphql, useLazyLoadQuery, usePreloadedQuery } from 'react-relay';
|
|
7
|
+
import FeatureTesterCard from './FeatureTesterCard.js';
|
|
8
|
+
import { EnsureFontdueContext } from '../FontdueContextProvider/index.js';
|
|
9
|
+
import loadSerializableQuery from '../../relay/loadSerializableQuery.js';
|
|
10
|
+
import useSerializablePreloadedQuery from '../../relay/useSerializablePreloadedQuery.js';
|
|
11
|
+
import FeatureTesterStandaloneQueryNode from '../../__generated__/FeatureTesterStandaloneQuery.graphql.js';
|
|
12
|
+
const query = (_FeatureTesterStandaloneQuery.hash && _FeatureTesterStandaloneQuery.hash !== "eddba300b2fd5e283ab1f8f787edc518" && console.error("The definition of 'FeatureTesterStandaloneQuery' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _FeatureTesterStandaloneQuery);
|
|
13
|
+
function FeatureTesterRender(_ref) {
|
|
14
|
+
var _data$viewer;
|
|
15
|
+
let {
|
|
16
|
+
data,
|
|
17
|
+
...rest
|
|
18
|
+
} = _ref;
|
|
19
|
+
const fontStyle = (_data$viewer = data.viewer) === null || _data$viewer === void 0 ? void 0 : _data$viewer.fontStyle;
|
|
20
|
+
if (!fontStyle) {
|
|
21
|
+
console.log('[FeatureTester]: No FontStyle found');
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return /*#__PURE__*/React.createElement(FeatureTesterCard, _extends({
|
|
25
|
+
fontStyle: fontStyle
|
|
26
|
+
}, rest));
|
|
27
|
+
}
|
|
28
|
+
export async function loadFeatureTesterQuery(variables, options) {
|
|
29
|
+
return loadSerializableQuery(FeatureTesterStandaloneQueryNode, {
|
|
30
|
+
familyName: variables.familyName,
|
|
31
|
+
styleName: variables.styleName
|
|
32
|
+
}, options);
|
|
33
|
+
}
|
|
34
|
+
export function FeatureTesterPreloadedRenderer(_ref2) {
|
|
35
|
+
let {
|
|
36
|
+
preloadedQuery,
|
|
37
|
+
...rest
|
|
38
|
+
} = _ref2;
|
|
39
|
+
const queryRef = useSerializablePreloadedQuery(preloadedQuery, 'store-or-network', query);
|
|
40
|
+
const data = usePreloadedQuery(query, queryRef);
|
|
41
|
+
return /*#__PURE__*/React.createElement(FeatureTesterRender, _extends({
|
|
42
|
+
data: data
|
|
43
|
+
}, rest));
|
|
44
|
+
}
|
|
45
|
+
function FeatureTesterLazyRenderer(_ref3) {
|
|
46
|
+
let {
|
|
47
|
+
familyName,
|
|
48
|
+
styleName,
|
|
49
|
+
...rest
|
|
50
|
+
} = _ref3;
|
|
51
|
+
const data = useLazyLoadQuery(query, {
|
|
52
|
+
familyName,
|
|
53
|
+
styleName
|
|
54
|
+
});
|
|
55
|
+
return /*#__PURE__*/React.createElement(FeatureTesterRender, _extends({
|
|
56
|
+
data: data
|
|
57
|
+
}, rest));
|
|
58
|
+
}
|
|
59
|
+
// Unified FeatureTester entry point. Accepts either a preloaded query
|
|
60
|
+
// (server-side preload path) or `{familyName, styleName}` (lazy path, used by
|
|
61
|
+
// the CDN custom element and inside an existing `<FontdueProvider>` tree).
|
|
62
|
+
export default function FeatureTester(props) {
|
|
63
|
+
return /*#__PURE__*/React.createElement(EnsureFontdueContext, {
|
|
64
|
+
config: props.config
|
|
65
|
+
}, 'preloadedQuery' in props && props.preloadedQuery ? /*#__PURE__*/React.createElement(FeatureTesterPreloadedRenderer, props) : /*#__PURE__*/React.createElement(FeatureTesterLazyRenderer, props));
|
|
66
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { FeatureTesterProps } from './index.js';
|
|
3
|
+
export type { FeatureTesterPreloadedQuery } from './index.js';
|
|
4
|
+
export declare function loadFeatureTesterQuery(): never;
|
|
5
|
+
export default function FeatureTester(props: Extract<FeatureTesterProps, {
|
|
6
|
+
familyName: string;
|
|
7
|
+
}>): Promise<React.JSX.Element>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import loadSerializableQuery from '../../relay/loadSerializableQuery.js';
|
|
4
|
+
import { FeatureTesterPreloadedRenderer } from './index.js';
|
|
5
|
+
import FeatureTesterStandaloneQueryNode from '../../__generated__/FeatureTesterStandaloneQuery.graphql.js';
|
|
6
|
+
// Stub for the RSC export condition. See FontdueProvider/index.server.tsx
|
|
7
|
+
// for the rationale.
|
|
8
|
+
export function loadFeatureTesterQuery() {
|
|
9
|
+
throw new Error("loadFeatureTesterQuery isn't needed in React Server Components — " + 'the <FeatureTester> server entrypoint awaits its query automatically. ' + 'Drop the manual call.');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Next RSC variant: awaits the query on the server and hands the response to
|
|
13
|
+
// the client `FeatureTesterPreloadedRenderer`. Lets pages just write
|
|
14
|
+
// `<FeatureTester familyName="..." styleName="..." feature="..." content="..." />`
|
|
15
|
+
// in an RSC without manually invoking `loadFeatureTesterQuery` + threading
|
|
16
|
+
// `preloadedQuery` through props.
|
|
17
|
+
export default async function FeatureTester(props) {
|
|
18
|
+
const {
|
|
19
|
+
familyName,
|
|
20
|
+
styleName,
|
|
21
|
+
...rest
|
|
22
|
+
} = props;
|
|
23
|
+
const preloadedQuery = await loadSerializableQuery(FeatureTesterStandaloneQueryNode, {
|
|
24
|
+
familyName,
|
|
25
|
+
styleName
|
|
26
|
+
});
|
|
27
|
+
return /*#__PURE__*/React.createElement(FeatureTesterPreloadedRenderer, _extends({
|
|
28
|
+
preloadedQuery: preloadedQuery
|
|
29
|
+
}, rest));
|
|
30
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
4
|
+
import _NodePasswordFormElementSlugQuery from "../../__generated__/NodePasswordFormElementSlugQuery.graphql.js";
|
|
5
|
+
import _NodePasswordFormElementIDQuery from "../../__generated__/NodePasswordFormElementIDQuery.graphql.js";
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { graphql, useLazyLoadQuery } from 'react-relay';
|
|
8
|
+
import NodePasswordForm from './index.js';
|
|
9
|
+
// Auto-detecting wrapper behind the <fontdue-node-password-form> custom element.
|
|
10
|
+
// Unlike the presentational React component (the default export of ./index, used
|
|
11
|
+
// when the server has already detected the lock), this queries the collection
|
|
12
|
+
// itself and renders the form only when access is denied — so it works dropped
|
|
13
|
+
// onto any page, hiding itself for a visitor who already has access.
|
|
14
|
+
|
|
15
|
+
const idQuery = (_NodePasswordFormElementIDQuery.hash && _NodePasswordFormElementIDQuery.hash !== "213a61ae079e4f57b7b197b0d2f5256a" && console.error("The definition of 'NodePasswordFormElementIDQuery' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _NodePasswordFormElementIDQuery);
|
|
16
|
+
function NodePasswordFormIDQueryRenderer(_ref) {
|
|
17
|
+
let {
|
|
18
|
+
collectionId,
|
|
19
|
+
...rest
|
|
20
|
+
} = _ref;
|
|
21
|
+
const data = useLazyLoadQuery(idQuery, {
|
|
22
|
+
collectionId
|
|
23
|
+
});
|
|
24
|
+
// The @catch directive surfaces the password-protection error as ok:false; the
|
|
25
|
+
// node is only locked then, so only then do we render the form (we don't want
|
|
26
|
+
// to show it to a visitor who already has access).
|
|
27
|
+
if (data.collection.ok === false) return /*#__PURE__*/React.createElement(NodePasswordForm, _extends({}, rest, {
|
|
28
|
+
collectionId: collectionId
|
|
29
|
+
}));
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const slugQuery = (_NodePasswordFormElementSlugQuery.hash && _NodePasswordFormElementSlugQuery.hash !== "200a33ca6a1f9e4e7e95b7100bbdd261" && console.error("The definition of 'NodePasswordFormElementSlugQuery' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _NodePasswordFormElementSlugQuery);
|
|
33
|
+
function NodePasswordFormSlugQueryRenderer(_ref2) {
|
|
34
|
+
var _data$viewer$slug;
|
|
35
|
+
let {
|
|
36
|
+
collectionSlug,
|
|
37
|
+
...rest
|
|
38
|
+
} = _ref2;
|
|
39
|
+
const data = useLazyLoadQuery(slugQuery, {
|
|
40
|
+
collectionSlug
|
|
41
|
+
});
|
|
42
|
+
// see note in NodePasswordFormIDQueryRenderer
|
|
43
|
+
if (((_data$viewer$slug = data.viewer.slug) === null || _data$viewer$slug === void 0 ? void 0 : _data$viewer$slug.collection.ok) === false) return /*#__PURE__*/React.createElement(NodePasswordForm, _extends({}, rest, {
|
|
44
|
+
collectionSlug: collectionSlug
|
|
45
|
+
}));
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
export default function NodePasswordFormElement(_ref3) {
|
|
49
|
+
let {
|
|
50
|
+
collectionId,
|
|
51
|
+
collectionSlug,
|
|
52
|
+
...rest
|
|
53
|
+
} = _ref3;
|
|
54
|
+
if (collectionId) {
|
|
55
|
+
return /*#__PURE__*/React.createElement(NodePasswordFormIDQueryRenderer, _extends({
|
|
56
|
+
collectionId: collectionId
|
|
57
|
+
}, rest));
|
|
58
|
+
}
|
|
59
|
+
if (collectionSlug) {
|
|
60
|
+
return /*#__PURE__*/React.createElement(NodePasswordFormSlugQueryRenderer, _extends({
|
|
61
|
+
collectionSlug: collectionSlug
|
|
62
|
+
}, rest));
|
|
63
|
+
}
|
|
64
|
+
throw new Error('NodePasswordForm expected either a collectionId or collectionSlug prop');
|
|
65
|
+
}
|
|
@@ -3,4 +3,19 @@ export interface NodePasswordForm_props {
|
|
|
3
3
|
collectionId?: string | null;
|
|
4
4
|
collectionSlug?: string | null;
|
|
5
5
|
}
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Password form for a collection you already know is locked. Render it when a
|
|
8
|
+
* collection comes back password-protected (see the per-framework guides): it
|
|
9
|
+
* commits the `accessNode` mutation, remembers the returned access token, and
|
|
10
|
+
* reloads so the now-unlocked collection renders.
|
|
11
|
+
*
|
|
12
|
+
* Unlike the `<fontdue-node-password-form>` custom element (which detects the
|
|
13
|
+
* locked state itself), this does no data fetching of its own, so it renders
|
|
14
|
+
* immediately on the server with no Suspense flash — the server already detected
|
|
15
|
+
* the lock.
|
|
16
|
+
*
|
|
17
|
+
* Self-wraps in `EnsureFontdueContext` so it works as a standalone island (e.g.
|
|
18
|
+
* an Astro `client:load`) without its own provider, and no-ops inside an outer
|
|
19
|
+
* `<FontdueProvider>` (Next/RR7/TanStack).
|
|
20
|
+
*/
|
|
21
|
+
export default function NodePasswordForm(props: NodePasswordForm_props): React.JSX.Element;
|